diff --git a/docs/source/components/bootloader.rst b/docs/source/components/bootloader.rst index a318184a5..71716e13d 100644 --- a/docs/source/components/bootloader.rst +++ b/docs/source/components/bootloader.rst @@ -5,17 +5,14 @@ Bootloader Depthai bootloader is a small program which aids in booting and updating bootloader or depthai application packages. -To be able to run hostless, the Depthai bootloader must be first flashed to the devices flash. -This step is required only once. +To be able to run standalone (:ref:`documentation here `), the Depthai bootloader must be first +flashed to the devices flash. This step is required only once. -Plug USB to the board -Flash bootloader using DeviceBootloader::flashBootloader (Check Example at the bottom) -Disconnect the board and switch the boot mode GPIO to the following settings: BOOT[4:0] : 01000 (see attached images for reference) -Reassemble the board +Once the device has the bootloader flashed, it will perform the same as before. Running pipelines with a host +connected doesn’t require any changes. -Once the device has the bootloader flashed, it will perform the same as before. Running pipelines with a host connected doesn’t require any changes. - -Suggested workflow is to perform as much of development as possible with the host connected as the iteration cycle is greatly improved. +Suggested workflow is to perform as much of development as possible with the host connected as the +iteration cycle is greatly improved. Once desired pipeline is created, use the following function to flash: :code:`DeviceBootloader::flash` @@ -54,42 +51,4 @@ Depthai application package (**.dap**) consists of: - Assets structure (section “assets”) - Asset storage (section “asset_storage”) -Example -####### - -Following section will show an example of: Flashing bootloader (needed only once) and flashing a created Pipeline “myExamplePipeline” to the device -(The example is written in Python, similar steps apply to C++) - -#. **Flashing bootloader** - - .. code-block:: python - - import depthai as dai - (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice() - bootloader = dai.DeviceBootloader(bl) - progress = lambda p : print(f'Flashing progress: {p*100:.1f}%') - bootloader.flashBootloader(progress) - - .. note:: - Make sure to switch GPIO BOOT mode settings (See image below for more details) - -#. **Flashing created pipeline** - - .. code-block:: python - - import depthai as dai - # ... - # Create Pipeline 'myExamplePipeline' - # ... - (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice() - bootloader = dai.DeviceBootloader(bl) - progress = lambda p : print(f'Flashing progress: {p*100:.1f}%') - bootloader.flash(progress, myExamplePipeline) - - -GPIO boot settings. Boot settings must be set as following: BOOT[4:0] : 01000 and GPIO58 (WAKEUP): 0 - -.. image:: /_static/images/components/boot-depthai.jpeg - :alt: boot-depthai - .. include:: ../includes/footer-short.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index b49af1911..00a6b71a5 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -65,6 +65,7 @@ node functionalities are presented with code. :caption: Tutorials: tutorials/hello_world.rst + tutorials/standalone_mode.rst tutorials/multiple.rst tutorials/maximize_fov.rst tutorials/debugging.rst diff --git a/docs/source/tutorials/standalone_mode.rst b/docs/source/tutorials/standalone_mode.rst new file mode 100644 index 000000000..27c0a5f20 --- /dev/null +++ b/docs/source/tutorials/standalone_mode.rst @@ -0,0 +1,157 @@ +Standalone mode +=============== + +**Standalone / Hostless / On-The-Edge mode** means that the OAK camera isn't connected to a host computer. This can +be achieved by first :ref:`flashing the bootloader ` and then :ref:`flashing the pipeline ` +and assets (NN models) to the OAK's flash memory. + +Standalone mode is **only possible on OAKs that have on-board flash** memory, which are currently `OAK IOT `__ +and `OAK POE `__ camera models. + +Converting a demo to standalone mode +#################################### + +Since there won't be any communication between the host and the device, you first need to remove all +:ref:`XLinkOut` and :ref:`XLinkIn` nodes. This means that the device will only communicate with the "outside world" +via either SPI (:ref:`SPIOut`/:ref:`SPIIn`) or :ref:`Script` node (GPIO/UART or network protocols if you have +OAK POE mode; HTTP/TCP/UDP...). + +Next thing you can also remove the host-side code, which usually looks something like this: + +.. code-block:: python + + with dai.Device(pipeline) as device: + videoQ = device.getOutputQueue("video") + faceDetQ = device.getOutputQueue("face_det") + nnQ = device.getOutputQueue("nn") + + while True: + frame = videoQ.get().getCvFrame() + # ... + + +After you remove all host-side code, you would only be left with the :ref:`Pipeline` definition (with nodes/links). +Since device no longer communicates with the host, you need to "route" your program's output through either SPI +or script node, as mentioned above. + +Flash bootloader +################ + +Execute the code below to flash the :ref:`Bootloader` to the device. The bootloader is packaged together with the +depthai, so if you have the latest depthai version, you will flash the latest bootloader version. This step +is required only once. + +.. code-block:: python + + import depthai as dai + (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice() + bootloader = dai.DeviceBootloader(bl) + progress = lambda p : print(f'Flashing progress: {p*100:.1f}%') + bootloader.flashBootloader(progress) + +Flash pipeline +############## + +After you have standalone :ref:`Pipeline` definition and :ref:`Bootloader` already flashed on the device, you +can start with flashing the pipeline. You can flash the pipeline with the following snippet: + +.. code-block:: python + + import depthai as dai + + pipeline = dai.Pipeline() + + # Define standalone pipeline; add nodes and link them + # cam = pipeline.create(dai.node.ColorCamera) + # script = pipeline.create(dai.node.Script) + # ... + + # 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) + +After successfully flashing the pipeline, it will get started automatically when you power up the device. +If you would like to change the flashed pipeline, simply re-flash it again. + +Clear flash +########### + +Since pipeline will start when powering the device, this can lead to unnecesary heating. If you would like to clear +the flashed pipeline, use the code snippet below. + +.. warning:: + Code below doesn't work yet. We will be adding "flashClear" helper function to the library. + +.. code-block:: python + + import depthai as dai + (f, bl) = dai.DeviceBootloader.getFirstAvailableDevice() + if not f: + print('No devices found, exiting...') + exit(-1) + + with dai.DeviceBootloader(bl) as bootloader: + bootloader.flashClear() + +Factory reset +############# + +In case you have soft-bricked your device, or just want to clear everything (flashed pipeline/assets and bootloader config), +we recommend running the factory reset script below. It will also flash the latest bootloader version. + +.. code-block:: python + + import depthai as dai + import tempfile + + blBinary = dai.DeviceBootloader.getEmbeddedBootloaderBinary(dai.DeviceBootloader.Type.NETWORK) + blBinary = blBinary + ([0xFF] * ((8 * 1024 * 1024 + 512) - len(blBinary))) + + with tempfile.NamedTemporaryFile() as tmpBlFw: + tmpBlFw.write(bytes(blBinary)) + + (f, device_info) = dai.DeviceBootloader.getFirstAvailableDevice() + if not f: + print('No devices found, exiting...') + exit(-1) + + with dai.DeviceBootloader(device_info, allowFlashingBootloader=True) as bootloader: + progress = lambda p : print(f'Factory reset progress: {p*100:.1f}%') + # Override SBR table, to prevent booting flashed application + [success, msg] = bootloader.flashBootloader(progress, tmpBlFw.name) + if success: + print('Successfully overwritten SBR table. Device should now be reacheable through PoE') + else: + print(f"Couldn't overwrite SBR table to unbrick the device. Error: {msg}") + +You can also **factory reset OAK POE at specific IP** if it's not reachable (not in same LAN). + +.. code-block:: python + + import depthai as dai + import tempfile + + blBinary = dai.DeviceBootloader.getEmbeddedBootloaderBinary(dai.DeviceBootloader.Type.NETWORK) + blBinary = blBinary + ([0xFF] * ((8 * 1024 * 1024 + 512) - len(blBinary))) + + with tempfile.NamedTemporaryFile() as tmpBlFw: + tmpBlFw.write(bytes(blBinary)) + + device_info = dai.DeviceInfo() + device_info.state = dai.XLinkDeviceState.X_LINK_BOOTLOADER + device_info.desc.protocol = dai.XLinkProtocol.X_LINK_TCP_IP + device_info.desc.name = "192.168.34.110" # Set IP here + + with dai.DeviceBootloader(device_info, allowFlashingBootloader=True) as bootloader: + progress = lambda p : print(f'Factory reset progress: {p*100:.1f}%') + # Override SBR table, to prevent booting flashed application + [success, msg] = bootloader.flashBootloader(progress, tmpBlFw.name) + if success: + print('Successfully overwritten SBR table. Device should now be reacheable through PoE') + else: + print(f"Couldn't overwrite SBR table to unbrick the device. Error: {msg}") + + +.. include:: ../includes/footer-short.rst