Skip to content

Commit e0355bc

Browse files
committed
Merge branch 'release_2.16.0.0' into main
2 parents 425d01a + 4c289a5 commit e0355bc

31 files changed

+579
-137
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ jobs:
177177
matrix:
178178
python-version: [3.6, 3.7, 3.8, 3.9, '3.10']
179179
python-architecture: [x64, x86]
180+
fail-fast: false
180181
steps:
181182
- name: Cache .hunter folder
182183
uses: actions/cache@v2
@@ -230,6 +231,7 @@ jobs:
230231
strategy:
231232
matrix:
232233
python-version: [3.6, 3.7, 3.8, 3.9, '3.10']
234+
fail-fast: false
233235
steps:
234236
- name: Cache .hunter folder
235237
uses: actions/cache@v2

CMakeLists.txt

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ if(NOT WIN32)
99
set(HUNTER_CONFIGURATION_TYPES "Release" CACHE STRING "Hunter dependencies list of build configurations")
1010
endif()
1111

12+
# Specify path separator
13+
set(SYS_PATH_SEPARATOR ";")
14+
if(UNIX)
15+
set(SYS_PATH_SEPARATOR ":")
16+
endif()
17+
1218
# Generate combined Hunter config
1319
file(READ depthai-core/cmake/Hunter/config.cmake depthai_core_hunter_config)
1420
file(READ cmake/Hunter/config.cmake hunter_config)
@@ -29,7 +35,7 @@ endif()
2935

3036
# Pybindings project
3137
set(TARGET_NAME depthai)
32-
project(depthai VERSION "1") # revision of bindings [depthai-core].[rev]
38+
project(depthai VERSION "0") # revision of bindings [depthai-core].[rev]
3339

3440
# Set default build type depending on context
3541
set(default_build_type "Release")
@@ -97,6 +103,23 @@ pybind11_add_module(${TARGET_NAME}
97103
src/log/LogBindings.cpp
98104
)
99105

106+
if(WIN32)
107+
# Copy dlls to target directory - Windows only
108+
# TARGET_RUNTIME_DLLS generator expression available since CMake 3.21
109+
if(CMAKE_VERSION VERSION_LESS "3.21")
110+
file(GLOB depthai_dll_libraries "${HUNTER_INSTALL_PREFIX}/bin/*.dll")
111+
else()
112+
set(depthai_dll_libraries "$<TARGET_RUNTIME_DLLS:${TARGET_NAME}>")
113+
endif()
114+
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND
115+
${CMAKE_COMMAND} -E copy ${depthai_dll_libraries} $<TARGET_FILE_DIR:${TARGET_NAME}>
116+
COMMAND_EXPAND_LISTS
117+
)
118+
119+
# Disable "d" postfix, so python can import the library as is
120+
set_target_properties(${TARGET_NAME} PROPERTIES DEBUG_POSTFIX "")
121+
endif()
122+
100123
# Add stubs (pyi) generation step after building bindings
101124
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" "from mypy import api" RESULT_VARIABLE error OUTPUT_QUIET ERROR_QUIET)
102125
if(error)
@@ -108,7 +131,12 @@ else()
108131
endif()
109132
message(STATUS "Mypy available, creating and checking stubs. Running with generate_stubs.py ${TARGET_NAME} ${bindings_directory}")
110133
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND
111-
${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_LIST_DIR}/generate_stubs.py" "${TARGET_NAME}" "${bindings_directory}"
134+
${CMAKE_COMMAND} -E env
135+
# PATH (dlls)
136+
"PATH=${HUNTER_INSTALL_PREFIX}/bin${SYS_PATH_SEPARATOR}$ENV{PATH}"
137+
# Python path (to find compiled module)
138+
"PYTHONPATH=$<TARGET_FILE_DIR:${TARGET_NAME}>${SYS_PATH_SEPARATOR}$ENV{PYTHONPATH}"
139+
${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_LIST_DIR}/generate_stubs.py" "${TARGET_NAME}" "$<TARGET_FILE_DIR:${TARGET_NAME}>"
112140
DEPENDS "${CMAKE_CURRENT_LIST_DIR}/generate_stubs.py"
113141
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
114142
)

ci/Dockerfile

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ RUN apt-get update && apt-get install -y wget build-essential cmake pkg-config l
44

55
ADD ci/docker_dependencies.sh .
66
RUN ./docker_dependencies.sh
7-
RUN wget https://github.com/libusb/libusb/releases/download/v1.0.24/libusb-1.0.24.tar.bz2
8-
RUN tar xf libusb-1.0.24.tar.bz2
9-
RUN cd libusb-1.0.24 && \
10-
./configure --disable-udev && \
11-
make -j && make install
12-
137

148
RUN pip install -U pip && pip install --extra-index-url https://www.piwheels.org/simple/ --prefer-binary opencv-python
159

depthai-core

Submodule depthai-core updated 48 files

docs/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ else()
4040
add_custom_target(sphinx ALL
4141
${CMAKE_COMMAND} -E env
4242
# Environment variables
43+
# PATH (dlls)
44+
"PATH=${HUNTER_INSTALL_PREFIX}/bin${SYS_PATH_SEPARATOR}$ENV{PATH}"
4345
# Python path (to find compiled module)
4446
"PYTHONPATH=$<TARGET_FILE_DIR:${TARGET_NAME}>${SYS_PATH_SEPARATOR}$ENV{PYTHONPATH}"
4547
# ASAN in case of sanitizers

docs/source/components/bootloader.rst

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,23 @@ Device Manager
2121
``device_manager.py`` is a Python helper that interfaces with device :ref:`Bootloader` and bootloader configuration.
2222
It can be found at `depthai-python/utilities <https://github.com/luxonis/depthai-python/tree/main/utilities>`__.
2323

24-
.. image:: https://user-images.githubusercontent.com/18037362/170479657-faacd06d-5f7e-4215-a821-005d58a5f379.png
24+
.. image:: https://user-images.githubusercontent.com/18037362/171629704-0f78f31a-1778-4338-8ac0-bdfb0d2d593f.png
2525

2626
Device Manager Usage
2727
--------------------
2828

2929
**About device tab** - Select a camera to see its metadata - like MxID, flashed bootloader version, device state etc.
3030

31-
* First, we need to select the device using the dropdown. You can click ``Search`` to search for all available cameras, either via USB port or on LAN (PoE OAKs).
31+
* First we have to select the device we want to connect (boot) to, you can select that using:
32+
33+
* **Dropdown** which contains found device MX Ids. Dropdown will only get updated when starting the app.
34+
* **Specify IP** button if your OAK PoE camera isn't in the same LAN.
35+
* **Search** feature - a new window will show that has a table with all available cameras (either via USB port or on LAN - OAK PoEs), their MxId, name, and status. Clicking on a table row will select that device and boot to it.
3236
* ``Flash newest Bootloader`` button will flash the ``newest bootloader`` to the device. You can select AUTO, USB or NETWORK bootloader.
3337

3438
* **AUTO** will select the connection type of bootloader with which the camera is currently connected to. If you are connected via USB (doing factory reset) to an OAK PoE camera, you shouldn't select AUTO, as it will flash USB bootloader.
3539
* **USB** bootloader will try to boot the application that is stored on flash memory. If it can't find flashed application, it will just behave as normal USB OAK - so it will wait until a host computer initializes the application.
3640
* **NETWORK** bootloader is used by the OAK PoE cameras, and is flashed at the factory. It handles network initialization so the OAK PoE cameras can be booted through the LAN.
37-
3841
* ``Factory reset`` will erase the whole flash content and re-flash it with only the USB or NETWORK bootloader. Flashed application (pipeline, assets) and bootloader configurations will be lost.
3942
* ``Boot into USB recovery mode`` will force eg. OAK PoE camera to be available through the USB connector, even if its boot pins are set to PoE booting. It is mostly used by our firmware developers.
4043

docs/source/components/device.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ When you create the device in the code, firmware is uploaded together with the p
4040
cfg = depthai.ImageManipConfig()
4141
input_q.send(cfg)
4242
43+
Connect to specified device
44+
###########################
45+
46+
If you have multiple devices and only want to connect to a specific one, or if your OAK PoE camera is outside of your
47+
subnet, you can specify the device (either with MxID, IP, or USB port name) you want to connect to.
48+
49+
.. code-block:: python
50+
51+
# Specify MXID, IP Address or USB path
52+
device_info = depthai.DeviceInfo("14442C108144F1D000") # MXID
53+
#device_info = depthai.DeviceInfo("192.168.1.44") # IP Address
54+
#device_info = depthai.DeviceInfo("3.3.3") # USB port name
55+
with depthai.Device(pipeline, device_info) as device:
56+
# ...
4357
4458
Multiple devices
4559
################

examples/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ function(add_python_example example_name python_script_path)
3333
add_custom_target(${example_name}
3434
${CMAKE_COMMAND} -E env
3535
# Environment variables
36+
# PATH (dlls)
37+
"PATH=${HUNTER_INSTALL_PREFIX}/bin${SYS_PATH_SEPARATOR}$ENV{PATH}"
3638
# Python path (to find compiled module)
3739
"PYTHONPATH=$<TARGET_FILE_DIR:${TARGET_NAME}>${SYS_PATH_SEPARATOR}$ENV{PYTHONPATH}"
3840
# ASAN in case of sanitizers
@@ -49,6 +51,8 @@ function(add_python_example example_name python_script_path)
4951
# Adds test with 5 seconds timeout and bumps all python warnings to errors
5052
add_test(NAME ${example_name} COMMAND
5153
${CMAKE_COMMAND} -E env
54+
# PATH (dlls)
55+
"PATH=${HUNTER_INSTALL_PREFIX}/bin${SYS_PATH_SEPARATOR}$ENV{PATH}"
5256
# Python path (to find compiled module)
5357
"PYTHONPATH=$<TARGET_FILE_DIR:${TARGET_NAME}>${SYS_PATH_SEPARATOR}$ENV{PYTHONPATH}"
5458
# ASAN in case of sanitizers
@@ -70,6 +74,8 @@ if(DEPTHAI_PYTHON_TEST_EXAMPLES)
7074
# Adds install requirements test with 5 minute timeout
7175
add_test(NAME install_requirements COMMAND
7276
${CMAKE_COMMAND} -E env
77+
# PATH (dlls)
78+
"PATH=${HUNTER_INSTALL_PREFIX}/bin${SYS_PATH_SEPARATOR}$ENV{PATH}"
7379
# Python path (to find compiled module)
7480
"PYTHONPATH=$<TARGET_FILE_DIR:${TARGET_NAME}>${SYS_PATH_SEPARATOR}$ENV{PYTHONPATH}"
7581
# ASAN in case of sanitizers

examples/IMU/imu_firmware_update.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env python3
2+
3+
import cv2
4+
import depthai as dai
5+
import time
6+
import math
7+
8+
print("Warning! Flashing IMU firmware can potentially soft brick your device and should be done with caution.")
9+
print("Do not unplug your device while the IMU firmware is flashing.")
10+
print("Type 'y' and press enter to proceed, otherwise exits: ")
11+
if input() != 'y':
12+
print("Prompt declined, exiting...")
13+
exit(-1)
14+
15+
# Create pipeline
16+
pipeline = dai.Pipeline()
17+
18+
# Define sources and outputs
19+
imu = pipeline.create(dai.node.IMU)
20+
xlinkOut = pipeline.create(dai.node.XLinkOut)
21+
22+
xlinkOut.setStreamName("imu")
23+
24+
# enable ACCELEROMETER_RAW at 500 hz rate
25+
imu.enableIMUSensor(dai.IMUSensor.ACCELEROMETER_RAW, 500)
26+
# enable GYROSCOPE_RAW at 400 hz rate
27+
imu.enableIMUSensor(dai.IMUSensor.GYROSCOPE_RAW, 400)
28+
# it's recommended to set both setBatchReportThreshold and setMaxBatchReports to 20 when integrating in a pipeline with a lot of input/output connections
29+
# above this threshold packets will be sent in batch of X, if the host is not blocked and USB bandwidth is available
30+
imu.setBatchReportThreshold(1)
31+
# maximum number of IMU packets in a batch, if it's reached device will block sending until host can receive it
32+
# if lower or equal to batchReportThreshold then the sending is always blocking on device
33+
# useful to reduce device's CPU load and number of lost packets, if CPU load is high on device side due to multiple nodes
34+
imu.setMaxBatchReports(10)
35+
36+
# Link plugins IMU -> XLINK
37+
imu.out.link(xlinkOut.input)
38+
39+
imu.enableFirmwareUpdate(True)
40+
41+
# Pipeline is defined, now we can connect to the device
42+
with dai.Device(pipeline) as device:
43+
44+
def timeDeltaToMilliS(delta) -> float:
45+
return delta.total_seconds()*1000
46+
47+
# Output queue for imu bulk packets
48+
imuQueue = device.getOutputQueue(name="imu", maxSize=50, blocking=False)
49+
baseTs = None
50+
while True:
51+
imuData = imuQueue.get() # blocking call, will wait until a new data has arrived
52+
53+
imuPackets = imuData.packets
54+
for imuPacket in imuPackets:
55+
acceleroValues = imuPacket.acceleroMeter
56+
gyroValues = imuPacket.gyroscope
57+
58+
acceleroTs = acceleroValues.timestamp.get()
59+
gyroTs = gyroValues.timestamp.get()
60+
if baseTs is None:
61+
baseTs = acceleroTs if acceleroTs < gyroTs else gyroTs
62+
acceleroTs = timeDeltaToMilliS(acceleroTs - baseTs)
63+
gyroTs = timeDeltaToMilliS(gyroTs - baseTs)
64+
65+
imuF = "{:.06f}"
66+
tsF = "{:.03f}"
67+
68+
print(f"Accelerometer timestamp: {tsF.format(acceleroTs)} ms")
69+
print(f"Accelerometer [m/s^2]: x: {imuF.format(acceleroValues.x)} y: {imuF.format(acceleroValues.y)} z: {imuF.format(acceleroValues.z)}")
70+
print(f"Gyroscope timestamp: {tsF.format(gyroTs)} ms")
71+
print(f"Gyroscope [rad/s]: x: {imuF.format(gyroValues.x)} y: {imuF.format(gyroValues.y)} z: {imuF.format(gyroValues.z)} ")
72+
73+
if cv2.waitKey(1) == ord('q'):
74+
break

examples/IMU/imu_rotation_vector.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
# enable ROTATION_VECTOR at 400 hz rate
1818
imu.enableIMUSensor(dai.IMUSensor.ROTATION_VECTOR, 400)
19+
# it's recommended to set both setBatchReportThreshold and setMaxBatchReports to 20 when integrating in a pipeline with a lot of input/output connections
1920
# above this threshold packets will be sent in batch of X, if the host is not blocked and USB bandwidth is available
2021
imu.setBatchReportThreshold(1)
2122
# maximum number of IMU packets in a batch, if it's reached device will block sending until host can receive it

examples/MobileNet/rgb_mobilenet.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@
2929
nn = pipeline.create(dai.node.MobileNetDetectionNetwork)
3030
xoutRgb = pipeline.create(dai.node.XLinkOut)
3131
nnOut = pipeline.create(dai.node.XLinkOut)
32+
nnNetworkOut = pipeline.create(dai.node.XLinkOut)
3233

3334
xoutRgb.setStreamName("rgb")
3435
nnOut.setStreamName("nn")
36+
nnNetworkOut.setStreamName("nnNetwork");
3537

3638
# Properties
3739
camRgb.setPreviewSize(300, 300)
@@ -51,13 +53,15 @@
5153

5254
camRgb.preview.link(nn.input)
5355
nn.out.link(nnOut.input)
56+
nn.outNetwork.link(nnNetworkOut.input);
5457

5558
# Connect to device and start pipeline
5659
with dai.Device(pipeline) as device:
5760

5861
# Output queues will be used to get the rgb frames and nn data from the outputs defined above
5962
qRgb = device.getOutputQueue(name="rgb", maxSize=4, blocking=False)
6063
qDet = device.getOutputQueue(name="nn", maxSize=4, blocking=False)
64+
qNN = device.getOutputQueue(name="nnNetwork", maxSize=4, blocking=False);
6165

6266
frame = None
6367
detections = []
@@ -81,15 +85,19 @@ def displayFrame(name, frame):
8185
# Show the frame
8286
cv2.imshow(name, frame)
8387

88+
printOutputLayersOnce = True
89+
8490
while True:
8591
if args.sync:
8692
# Use blocking get() call to catch frame and inference result synced
8793
inRgb = qRgb.get()
8894
inDet = qDet.get()
95+
inNN = qNN.get()
8996
else:
9097
# Instead of get (blocking), we use tryGet (non-blocking) which will return the available data or None otherwise
9198
inRgb = qRgb.tryGet()
9299
inDet = qDet.tryGet()
100+
inNN = qNN.tryGet()
93101

94102
if inRgb is not None:
95103
frame = inRgb.getCvFrame()
@@ -100,6 +108,13 @@ def displayFrame(name, frame):
100108
detections = inDet.detections
101109
counter += 1
102110

111+
if printOutputLayersOnce and inNN is not None:
112+
toPrint = 'Output layer names:'
113+
for ten in inNN.getAllLayerNames():
114+
toPrint = f'{toPrint} {ten},'
115+
print(toPrint)
116+
printOutputLayersOnce = False;
117+
103118
# If the frame is available, draw bounding boxes on it and show the frame
104119
if frame is not None:
105120
displayFrame("rgb", frame)

0 commit comments

Comments
 (0)