Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 6 additions & 47 deletions docs/source/components/bootloader.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <Standalone mode>`), 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`

Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
157 changes: 157 additions & 0 deletions docs/source/tutorials/standalone_mode.rst
Original file line number Diff line number Diff line change
@@ -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 <Flash bootloader>` and then :ref:`flashing the pipeline <Flash 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 <https://docs.luxonis.com/projects/hardware/en/latest/#iot-designs>`__
and `OAK POE <https://docs.luxonis.com/projects/hardware/en/latest/#poe-designs>`__ 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