From 991156488b89215d1b8b362f35885ddf7e9b81b4 Mon Sep 17 00:00:00 2001 From: Jan Gutsche Date: Sat, 11 Apr 2026 18:19:36 +0200 Subject: [PATCH] git subrepo clone git@github.com:stereolabs/zed-ros2-wrapper.git src/lib/zed-ros2-wrapper subrepo: subdir: "src/lib/zed-ros2-wrapper" merged: "b47c72779" upstream: origin: "git@github.com:stereolabs/zed-ros2-wrapper.git" branch: "master" commit: "b47c72779" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo" commit: "ea10886" --- .../ISSUE_TEMPLATE/1_feature_request.yml | 43 + .../.github/ISSUE_TEMPLATE/2_bug_report.yml | 87 + .../.github/ISSUE_TEMPLATE/config.yml | 12 + .../.github/workflows/stale_issues.yml | 23 + src/lib/zed-ros2-wrapper/.gitignore | 98 + src/lib/zed-ros2-wrapper/.gitrepo | 12 + src/lib/zed-ros2-wrapper/CHANGELOG.rst | 603 + src/lib/zed-ros2-wrapper/CONTRIBUTING.md | 50 + src/lib/zed-ros2-wrapper/LICENSE | 251 + src/lib/zed-ros2-wrapper/README.md | 330 + .../docker/Dockerfile.desktop-humble | 134 + .../docker/Dockerfile.l4t-humble | 118 + src/lib/zed-ros2-wrapper/docker/README.md | 149 + ...erfile_from_sdk_ubuntu_and_cuda_version.sh | 93 + ...ild_dockerfile_from_sdk_and_l4T_version.sh | 85 + .../zed-ros2-wrapper/docker/ros_entrypoint.sh | 26 + .../docker/ros_entrypoint_jetson.sh | 26 + src/lib/zed-ros2-wrapper/images/.gitkeep | 0 .../images/Picto+STEREOLABS_Black.jpg | Bin 0 -> 15698 bytes .../images/PointCloud_Depth_ROS.jpg | Bin 0 -> 154842 bytes src/lib/zed-ros2-wrapper/images/depth.jpg | Bin 0 -> 55257 bytes .../zed-ros2-wrapper/images/nitros-graph.gif | Bin 0 -> 592371 bytes .../zed-ros2-wrapper/images/point_cloud.jpg | Bin 0 -> 122887 bytes src/lib/zed-ros2-wrapper/images/rgb.jpg | Bin 0 -> 151430 bytes src/lib/zed-ros2-wrapper/images/sim_rviz.jpg | Bin 0 -> 305434 bytes .../zed-ros2-wrapper/images/zed_shelves.jpg | Bin 0 -> 229060 bytes .../zed_components/CMakeLists.txt | 332 + .../zed_components/package.xml | 59 + .../zed_components/src/include/sl_version.hpp | 33 + .../src/include/visibility_control.hpp | 61 + .../src/tools/include/gnss_replay.hpp | 38 + .../src/tools/include/sl_logging.hpp | 210 + .../src/tools/include/sl_tools.hpp | 405 + .../src/tools/include/sl_types.hpp | 204 + .../src/tools/include/sl_win_avg.hpp | 51 + .../src/tools/src/gnss_replay.cpp | 328 + .../zed_components/src/tools/src/sl_tools.cpp | 731 ++ .../zed_components/src/tools/src/sl_types.cpp | 48 + .../src/tools/src/sl_win_avg.cpp | 71 + .../include/cost_traversability.hpp | 71 + .../include/zed_camera_component.hpp | 1191 ++ .../zed_camera/src/cost_traversability.cpp | 194 + .../src/zed_camera_component_bodytrk.cpp | 430 + .../src/zed_camera_component_main.cpp | 10032 ++++++++++++++++ .../src/zed_camera_component_objdet.cpp | 1211 ++ .../src/zed_camera_component_video_depth.cpp | 3288 +++++ .../include/zed_camera_one_component.hpp | 549 + .../src/zed_camera_one_component_main.cpp | 2605 ++++ .../src/zed_camera_one_component_sensors.cpp | 631 + .../src/zed_camera_one_component_video.cpp | 1121 ++ .../zed-ros2-wrapper/zed_debug/CMakeLists.txt | 163 + src/lib/zed-ros2-wrapper/zed_debug/README.md | 97 + .../zed_debug/config/common_mono.yaml | 84 + .../zed_debug/config/common_stereo.yaml | 220 + .../config/custom_object_detection.yaml | 1623 +++ .../zed_debug/config/object_detection.yaml | 26 + .../zed_debug/config/virtual.yaml | 27 + .../zed_debug/config/zed.yaml | 19 + .../zed_debug/config/zed2.yaml | 20 + .../zed_debug/config/zed2i.yaml | 21 + .../zed_debug/config/zedm.yaml | 20 + .../zed_debug/config/zedx.yaml | 28 + .../zed_debug/config/zedxhdr.yaml | 28 + .../zed_debug/config/zedxhdrmax.yaml | 28 + .../zed_debug/config/zedxhdrmini.yaml | 28 + .../zed_debug/config/zedxm.yaml | 28 + .../zed_debug/config/zedxone4k.yaml | 14 + .../zed_debug/config/zedxonegs.yaml | 10 + .../zed_debug/config/zedxonehdr.yaml | 10 + .../launch/zed_camera_debug.launch.py | 436 + .../zed-ros2-wrapper/zed_debug/package.xml | 34 + .../zed_debug/src/zed_debug_proc.cpp | 64 + .../zed-ros2-wrapper/zed_ros2/CMakeLists.txt | 67 + src/lib/zed-ros2-wrapper/zed_ros2/package.xml | 33 + .../zed_wrapper/CMakeLists.txt | 78 + .../zed_wrapper/config/common_mono.yaml | 84 + .../zed_wrapper/config/common_stereo.yaml | 220 + .../config/custom_object_detection.yaml | 1943 +++ .../zed_wrapper/config/object_detection.yaml | 26 + .../zed_wrapper/config/virtual.yaml | 27 + .../zed_wrapper/config/zed.yaml | 19 + .../zed_wrapper/config/zed2.yaml | 20 + .../zed_wrapper/config/zed2i.yaml | 21 + .../zed_wrapper/config/zedm.yaml | 20 + .../zed_wrapper/config/zedx.yaml | 28 + .../zed_wrapper/config/zedxhdr.yaml | 28 + .../zed_wrapper/config/zedxhdrmax.yaml | 28 + .../zed_wrapper/config/zedxhdrmini.yaml | 28 + .../zed_wrapper/config/zedxm.yaml | 28 + .../zed_wrapper/config/zedxone4k.yaml | 14 + .../zed_wrapper/config/zedxonegs.yaml | 10 + .../zed_wrapper/config/zedxonehdr.yaml | 10 + .../zed_wrapper/launch/zed_camera.launch.py | 604 + .../zed-ros2-wrapper/zed_wrapper/package.xml | 38 + .../zed_wrapper/urdf/zed_descr.urdf.xacro | 33 + .../zed_wrapper/urdf/zed_macro.urdf.xacro | 315 + 96 files changed, 32784 insertions(+) create mode 100644 src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/1_feature_request.yml create mode 100644 src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/2_bug_report.yml create mode 100644 src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/config.yml create mode 100644 src/lib/zed-ros2-wrapper/.github/workflows/stale_issues.yml create mode 100644 src/lib/zed-ros2-wrapper/.gitignore create mode 100644 src/lib/zed-ros2-wrapper/.gitrepo create mode 100644 src/lib/zed-ros2-wrapper/CHANGELOG.rst create mode 100644 src/lib/zed-ros2-wrapper/CONTRIBUTING.md create mode 100644 src/lib/zed-ros2-wrapper/LICENSE create mode 100644 src/lib/zed-ros2-wrapper/README.md create mode 100644 src/lib/zed-ros2-wrapper/docker/Dockerfile.desktop-humble create mode 100644 src/lib/zed-ros2-wrapper/docker/Dockerfile.l4t-humble create mode 100644 src/lib/zed-ros2-wrapper/docker/README.md create mode 100755 src/lib/zed-ros2-wrapper/docker/desktop_build_dockerfile_from_sdk_ubuntu_and_cuda_version.sh create mode 100755 src/lib/zed-ros2-wrapper/docker/jetson_build_dockerfile_from_sdk_and_l4T_version.sh create mode 100644 src/lib/zed-ros2-wrapper/docker/ros_entrypoint.sh create mode 100644 src/lib/zed-ros2-wrapper/docker/ros_entrypoint_jetson.sh create mode 100644 src/lib/zed-ros2-wrapper/images/.gitkeep create mode 100644 src/lib/zed-ros2-wrapper/images/Picto+STEREOLABS_Black.jpg create mode 100644 src/lib/zed-ros2-wrapper/images/PointCloud_Depth_ROS.jpg create mode 100644 src/lib/zed-ros2-wrapper/images/depth.jpg create mode 100644 src/lib/zed-ros2-wrapper/images/nitros-graph.gif create mode 100644 src/lib/zed-ros2-wrapper/images/point_cloud.jpg create mode 100644 src/lib/zed-ros2-wrapper/images/rgb.jpg create mode 100644 src/lib/zed-ros2-wrapper/images/sim_rviz.jpg create mode 100644 src/lib/zed-ros2-wrapper/images/zed_shelves.jpg create mode 100644 src/lib/zed-ros2-wrapper/zed_components/CMakeLists.txt create mode 100644 src/lib/zed-ros2-wrapper/zed_components/package.xml create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/include/sl_version.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/include/visibility_control.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/include/gnss_replay.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_logging.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_tools.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_types.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_win_avg.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/src/gnss_replay.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_tools.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_types.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_win_avg.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/cost_traversability.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/zed_camera_component.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/cost_traversability.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_bodytrk.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_main.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_objdet.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_video_depth.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/include/zed_camera_one_component.hpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_main.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_sensors.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_video.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/CMakeLists.txt create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/README.md create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/common_mono.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/common_stereo.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/custom_object_detection.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/object_detection.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/virtual.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zed.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zed2.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zed2i.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedm.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedx.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdr.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmax.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmini.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedxm.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedxone4k.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedxonegs.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/config/zedxonehdr.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/launch/zed_camera_debug.launch.py create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/package.xml create mode 100644 src/lib/zed-ros2-wrapper/zed_debug/src/zed_debug_proc.cpp create mode 100644 src/lib/zed-ros2-wrapper/zed_ros2/CMakeLists.txt create mode 100644 src/lib/zed-ros2-wrapper/zed_ros2/package.xml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/CMakeLists.txt create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/common_mono.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/common_stereo.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/custom_object_detection.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/object_detection.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/virtual.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zed.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2i.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedm.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedx.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdr.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmax.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmini.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxm.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxone4k.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonegs.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonehdr.yaml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/launch/zed_camera.launch.py create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/package.xml create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_descr.urdf.xacro create mode 100644 src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_macro.urdf.xacro diff --git a/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/1_feature_request.yml b/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/1_feature_request.yml new file mode 100644 index 0000000000..7b161ecdb8 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/1_feature_request.yml @@ -0,0 +1,43 @@ +name: Feature request 🧭 +description: Suggest an idea for this project. +labels: "feature_request" +body: + - type: markdown + attributes: + value: | + # Welcome 👋 + + Thanks for taking the time to fill out this feature request module. + Please fill out each section below. This info allows Stereolabs developers to correctly evaluate your request. + + Useful Links: + - Documentation: https://www.stereolabs.com/docs/ + - Stereolabs support: https://support.stereolabs.com/hc/en-us/ + - type: checkboxes + attributes: + label: Preliminary Checks + description: Please make sure that you verify each checkbox and follow the instructions for them. + options: + - label: "This issue is not a duplicate. Before opening a new issue, please search existing issues." + required: true + - label: "This issue is not a question, bug report, or anything other than a feature request directly related to this project." + required: true + - type: textarea + attributes: + label: Proposal + description: "What would you like to have as a new feature?" + placeholder: "A clear and concise description of what you want to happen." + validations: + required: true + - type: textarea + attributes: + label: Use-Case + description: "How would this help you?" + placeholder: "Tell us more what you'd like to achieve." + validations: + required: false + - type: textarea + id: anything-else + attributes: + label: Anything else? + description: "Let us know if you have anything else to share" diff --git a/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/2_bug_report.yml b/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/2_bug_report.yml new file mode 100644 index 0000000000..30ac21e9e1 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/2_bug_report.yml @@ -0,0 +1,87 @@ +name: Bug Report 🐛 +description: Something isn't working as expected? Report your bugs here. +labels: "bug" +body: + - type: markdown + attributes: + value: | + # Welcome 👋 + + Thanks for taking the time to fill out this bug report. + Please fill out each section below. This info allows Stereolabs developers to diagnose (and fix!) your issue as quickly as possible. Otherwise we might need to close the issue without e.g. clear reproduction steps. + + Bug reports also shoulnd't be used for generic questions, please use the [Stereolabs Community forum](https://community.stereolabs.com/) instead. + + Useful Links: + - Documentation: https://www.stereolabs.com/docs/ + - Stereolabs support: https://support.stereolabs.com/hc/en-us/ + - type: checkboxes + attributes: + label: Preliminary Checks + description: Please make sure that you verify each checkbox and follow the instructions for them. + options: + - label: "This issue is not a duplicate. Before opening a new issue, please search existing issues." + required: true + - label: "This issue is not a question, feature request, or anything other than a bug report directly related to this project." + required: true + - type: textarea + attributes: + label: Description + description: Describe the issue that you're seeing. + placeholder: Be as precise as you can. Feel free to share screenshots, videos, or data. The more information you provide the easier will be to provide you with a fast solution. + validations: + required: true + - type: textarea + attributes: + label: Steps to Reproduce + description: Clear steps describing how to reproduce the issue. + value: | + 1. + 2. + 3. + ... + validations: + required: true + - type: textarea + attributes: + label: Expected Result + description: Describe what you expected to happen. + validations: + required: true + - type: textarea + attributes: + label: Actual Result + description: Describe what actually happened. + validations: + required: true + - type: dropdown + attributes: + label: ZED Camera model + description: What model of ZED camera are you using? + options: + - "ZED" + - "ZED Mini" + - "ZED2" + - "ZED2i" + validations: + required: true + - type: textarea + attributes: + label: Environment + render: shell + description: Useful information about your system. + placeholder: | + OS: Operating System + CPU: e.g. ARM + GPU: Nvidia Jetson Xavier NX + ZED SDK version: e.g. v3.5.3 + Other info: e.g. ROS Melodic + validations: + required: true + - type: textarea + attributes: + label: Anything else? + description: Please add any other information or comment that you think may be useful for solving the problem + placeholder: + validations: + required: false diff --git a/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/config.yml b/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..bf09243583 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +blank_issues_enabled: false +contact_links: + - name: Online Documentation + url: https://www.stereolabs.com/docs/ + about: Check out the Stereolabs documentation for answers to common questions. + - name: Stereolabs Community + url: https://community.stereolabs.com/ + about: Ask questions, request features & discuss with other users and developers. + - name: Stereolabs Twitter + url: https://twitter.com/Stereolabs3D + about: The official Stereolabs Twitter account to ask questions, comment our products and share your projects with the ZED community. + diff --git a/src/lib/zed-ros2-wrapper/.github/workflows/stale_issues.yml b/src/lib/zed-ros2-wrapper/.github/workflows/stale_issues.yml new file mode 100644 index 0000000000..9e01bd5910 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/.github/workflows/stale_issues.yml @@ -0,0 +1,23 @@ +name: 'Stale issue handler' +on: + workflow_dispatch: + schedule: + - cron: '00 00 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@main + id: stale + with: + stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment otherwise it will be automatically closed in 5 days' + stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment otherwise it will be automatically closed in 5 days' + days-before-stale: 30 + days-before-close: 5 + operations-per-run: 1500 + exempt-issue-labels: 'feature_request' + exempt-pr-labels: 'feature_request' + enable-statistics: 'true' + close-issue-label: 'closed_for_stale' + close-pr-label: 'closed_for_stale' diff --git a/src/lib/zed-ros2-wrapper/.gitignore b/src/lib/zed-ros2-wrapper/.gitignore new file mode 100644 index 0000000000..87df7b98a9 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/.gitignore @@ -0,0 +1,98 @@ +devel/ +logs/ +build/ +log/ +install/ +bin/ +lib/ +msg_gen/ +srv_gen/ +msg/*Action.msg +msg/*ActionFeedback.msg +msg/*ActionGoal.msg +msg/*ActionResult.msg +msg/*Feedback.msg +msg/*Goal.msg +msg/*Result.msg +msg/_*.py +build_isolated/ +devel_isolated/ + +# Generated by dynamic reconfigure +*.cfgc +/cfg/cpp/ +/cfg/*.py + +# Ignore generated docs +*.dox +*.wikidoc + +# eclipse stuff +.project +.cproject + +# qcreator stuff +CMakeLists.txt.user + +srv/_*.py +*.pcd +*.pyc +qtcreator-* +*.user + +/planning/cfg +/planning/docs +/planning/src + +*~ + +# Emacs +.#* + +# Catkin custom files +CATKIN_IGNORE + +# C++ objects and libs + +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es + +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +Makefile* +*build-* + +# QtCreator + +*.autosave + +# QtCtreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCtreator CMake +CMakeLists.txt.user* + +# VSCode +.vscode + +# TMP folders +docker/tmp_sources diff --git a/src/lib/zed-ros2-wrapper/.gitrepo b/src/lib/zed-ros2-wrapper/.gitrepo new file mode 100644 index 0000000000..a9407024c9 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme +; +[subrepo] + remote = git@github.com:stereolabs/zed-ros2-wrapper.git + branch = master + commit = b47c72779add6d58a4dba9c888b9ea529f6ae448 + parent = b16d3e70bda13036769caabb9e53982d75a89785 + method = merge + cmdver = 0.4.9 diff --git a/src/lib/zed-ros2-wrapper/CHANGELOG.rst b/src/lib/zed-ros2-wrapper/CHANGELOG.rst new file mode 100644 index 0000000000..880bc52f5c --- /dev/null +++ b/src/lib/zed-ros2-wrapper/CHANGELOG.rst @@ -0,0 +1,603 @@ +LATEST CHANGES +============== + +v5.2.2 +---------- +- Default Positional Tracking mode changed back to `GEN_1` until the stability and reliability of `GEN_3` is improved. + Users can still select a specific mode by setting the `pos_tracking.pos_tracking_mode` parameter to `GEN_1`, `GEN_2`, or `GEN_3` according to their needs and preferences. +- Modified node behaviors when Positional Tracking is disabled [`pos_tracking.pos_tracking_enabled: false`]: + + - `publish_tf` is automatically disabled. + - The `odom` related topics are no longer advertised. + - The `pose` related topics are no longer advertised. + - The GNSS fusion is automatically disabled. + - The Plane Detection is automatically disabled. + - The Positional Tracking services are no longer advertised. + - Depth stability follows the ZED SDK behaviors. + - Object Tracking follows the ZED SDK behaviors. + - Body Tracking follows the ZED SDK behaviors. + +- Add new parameter `debug.debug_dyn_params` to enable debug logs for dynamic parameters changes. + + - Dynamic parameters related logs are now displayed only if the new debug parameter `debug.debug_dyn_params` is set to `true` to avoid log spam when changing dynamic parameters. + +v5.2.1 +------ +- Added the parameter `general.grab_compute_capping_fps` to define a computation upper limit to the grab frequency. + + - This can be useful to get a known constant fixed rate or limit the computation load while keeping a short exposure time by setting a high camera capture framerate. + - If set to 0, the grab compute capping will be disabled, and the ZED SDK will process data at the grab rate. +- URDF now belongs to the `zed_description` package, which is now a dependency of the `zed_wrapper` package. This allows to use the URDF files of the ZED ROS2 Wrapper in other packages without depending on the whole wrapper. + + - The `zed_description` is available in binary form for ROS 2 Humble, Jazzy, and Rolling and can be installed with `sudo apt install ros-$ROS_DISTRO-zed-description` + +v5.2.0 +------ +- Removed the `zed_wrapper/urdf/include/materials.urdf.xacro` file and moved the material settings directly in the `zed_macro.urdf.xacro` file to avoid possible conflicts in multi-camera configurations. Thx @davesarmoury for the fix +- Added the `enable_localization_only` parameter to the configuration to allow the camera to localize in the loaded area memory without updating the map with new information. +- Added support for the ZED SDK Positional Tracking 2D mode if the SDK version is 5.1 or higher. +- Added the `zed_debug` package for debugging ZED Components by loading them in a single C++ process. +- Add `enable_depth` service to disable depth processing at runtime +- Positional Tracking `GEN_3` is now the default mode when using ZED SDK v5.2 or newer, providing improved stability and performance. The `GEN_2` mode is still available as an option for users who prefer it or need it for specific use cases. +- When using GEN_3 with ZED SDK v5.2 or newer, Positional Tracking continues to provide localization feedback even if depth is disabled at runtime or when the node starts by setting the `depth.depth_mode` parameter to `NONE`. +- New diagnostic information regarding Positional Tracking status: "Mode", "Odometry Status", "Spatial Memory Status", "Tracking Fusion Status". + +v5.1.0 +------ +- Changed ZED Camera image topic names to match the cleaner convention used by ZED X One cameras: + + - **NOTE** THIS IS A BREAKING CHANGE. + - Left sensor topics: + + - From `~/left/image_rect_color` to `~/left/color/rect/image` + - From `~/left_raw/image_raw_color` to `~/left/color/raw/image` + - From `~/left_gray/image_rect_gray` to `~/left/gray/rect/image` + - From `~/left_raw_gray/image_raw_gray` to `~/left/gray/raw/image` + + - Right sensor topics: + + - From `~/right/image_rect_color` to `~/right/color/rect/image` + - From `~/right_raw/image_raw_color` to `~/right/color/raw/image` + - From `~/right_gray/image_rect_gray` to `~/right/gray/rect/image` + - From `~/right_raw_gray/image_raw_gray` to `~/right/gray/raw/image` + + - RGB sensor topics (corresponding to the left sensor for the Stereo cameras): + + - From `~/rgb/image_rect_color` to `~/rgb/color/rect/image` + - From `~/rgb_raw/image_raw_color` to `~/rgb/color/raw/image` + - From `~/rgb_gray/image_rect_gray` to `~/rgb/gray/rect/image` + - From `~/rgb_raw_gray/image_raw_gray` to `~/rgb/gray/raw/image` + +- Added parameters to select what topics will be advertised when the node starts: + + - **NOTE** THIS IS A BREAKING CHANGE. TOPICS MAY NO LONGER BE AVAILABLE IF NOT ENABLED IN THE DEFAULT CONFIGURATION. Please check what topic you use and set the relevant parameter to `true`. + - `general.publish_status`: Advertise the status topics that are published only if a node subscribes to them + - `video.publish_rgb`: Advertise the RGB image topics that are published only if a node subscribes to them + - `video.publish_left_right`: Advertise the left and right image topics that are published only if a node subscribes to them + - `video.publish_raw`: Advertise the raw image topics that are published only if a node subscribes to them + - `video.publish_gray`: Advertise the gray image topics that are published only if a node subscribes to them + - `video.publish_stereo`: Advertise the stereo image topic that is published only if a node subscribes to it + - `sensors.publish_imu`: Advertise the IMU topic that is published only if a node subscribes to it + - `sensors.publish_imu_raw`: Advertise the raw IMU topic that is published only if a node subscribes to it + - `sensors.publish_cam_imu_transf`: Advertise the IMU transformation topic that is published only if a node subscribes to it + - `sensors.publish_mag`: Advertise the magnetometer topic that is published only if a node subscribes to it + - `sensors.publish_baro`: Advertise the barometer topic that is published only if a node subscribes to it + - `sensors.publish_temp`: Advertise the temperature topics that are published only if a node subscribes to them + - `region_of_interest.publish_roi_mask`: Advertise the ROI mask image topic that is published only if a node subscribes to it + - `depth.publish_depth_map`: Advertise the depth map topics that are published only if a node subscribes to them + - `depth.publish_depth_info`: Advertise the depth info topic that is published only if a node subscribes to it + - `depth.publish_point_cloud`: Advertise the point cloud topic that is published only if a node subscribes to it + - `depth.publish_depth_confidence`: Advertise the depth confidence topic that is published only if a node subscribes to it + - `depth.publish_disparity`: Advertise the disparity topic that is published only if a node subscribes to it + - `pos_tracking.publish_odom_pose`: Advertise the odometry and pose topics that are published only if a node subscribes to them + - `pos_tracking.publish_pose_cov`: Advertise the pose with covariance topic that is published only if a node subscribes to it + - `pos_tracking.publish_cam_path`: Advertise the camera odometry and pose path topics that are published only if a node subscribes to them + - `mapping.publish_det_plane`: Advertise the plane detection topics that is published only if a node subscribes to it + +- Added topic enabler feature to `sl::CameraOne` + + - **NOTE** THIS IS A BREAKING CHANGE. TOPICS MAY NO LONGER BE AVAILABLE IF NOT ENABLED IN THE DEFAULT CONFIGURATION. Please check what topic you use and set the relevant parameter to `true`. + - Added parameter `video.publish_rgb` to enable/disable RGB image publishing + - Added parameter `video.publish_raw` to enable/disable raw image publishing + - Added parameter `video.publish_gray` to enable/disable gray image publishing + - Added parameter `sensors.publish_imu`: Advertise the IMU topic that is published only if a node subscribes to it + - Added parameter `sensors.publish_imu_raw`: Advertise the raw IMU topic that is published only if a node subscribes to it + - Added parameter `sensors.publish_temp`: Advertise the temperature topics that are published only if a node subscribes to them + +- Enabled Isaac ROS NITROS integration for ZED X One cameras +- Added debug parameter `debug.debug_nitros` to enable debug logs for NITROS-related operations. +- Added debug parameter `debug.use_pub_timestamps` to use the current ROS time for the message timestamp instead of the camera timestamp. + This is useful to test data communication latency. +- Added `camera_info` in transport namespace to reflect `rviz2` requirements with the Camera plugin. + + - Added new `camInfoPubTrans` publisher for each image topic to publish the `camera_info` in the transport namespace. + - Updated `publishImageWithInfo` method to handle the new `camInfoPubTrans` publisher. + +- Added 3D visualization of the positional tracking landmarks as a point cloud on topic `~/pose/landmarks` (only with GEN_2 and GEN_3 positional tracking modes): + + - Added parameter `pos_tracking.publish_3d_landmarks` to enable/disable landmarks publishing + - Added parameter `pos_tracking.publish_lm_skip_frame` to set the frequency of landmarks publishing (0 to publish every frame) + +- Removed Point Cloud Transport as a required dependency. Point Cloud Transport is now only automatically enabled if the `point_cloud_transport` package is installed on the system. +- Removed FFMPEG Image Transport support because of a problem with the Humble distribution not allowing to set the transport parameters, and the lack of compatibility with NVIDIA® Jetson. +- Improved diagnostic information for 3D Mapping status in diagnostics +- Fixed random crash when stopping 3D Mapping +- Fixed a bug that forced the maximum publishing rate of the point cloud topic to 15 Hz with SVO files +- Set the default mode for positional tracking to `GEN_2` waiting for improvements in `GEN_3` stability +- Remapped `robot_description` topic to `_description` to allow multi-camera URDF integration +- Changed minimum depth value to 0.01 meters when using ZED SDK v5.1 or higher +- Added debug option for TF broadcasting + + - Improved TF debug logs to show frame transformations when enabled + +- Static baseline information from URDF is now overwritten by the real baseline value retrieved from the camera calibration file. +- Removed mandatory `custom_baseline` launch argument for virtual stereo cameras made with two ZED X One cameras. + The value is retrieved from the calibration file. +- IMU TF is now broadcast as static if IPC is disabled. +- IMU Transform topic is now published with TRANSIENT LOCAL durability if IPC is disabled. +- Fixed `camera_info` publishing when no image topics are subscribed +- Loop Closure log event is now displayed only in DEBUG mode to reduce log spam +- Renamed camera optical frames to comply with ROS conventions: + + - **NOTE** THIS IS A BREAKING CHANGE. Please update your TF references accordingly. + - From `_left_camera_optical_frame` to `_left_camera_frame_optical` + - From `_right_camera_optical_frame` to `_right_camera_frame_optical` + - From `_camera_optical_frame` to `_rgb_camera_frame_optical` + +- Added twist information to the `odom` topic +- Added support for the new Virtual Stereo API with SDK v5.1. + + - New launch arguments to setup the virtual camera: `serial_numbers` and `camera_ids` + - New `ZedCamera` component parameters to setup the virtual camera: `general.virtual_serial_numbers` and `general.virtual_camera_ids` + - **NOTE** ZED MEDIA SERVER IS NO LONGER REQUIRED to create a virtual Stereo camera using two ZED X One cameras. + +- Added 24-bit BGR image mode + + - Added parameter `video.enable_24bit_output` to enable/disable 24-bit BGR image publishing to `common_stereo.yaml` and `common_mono.yaml` configuration files + - **NOTE**: `video.enable_24bit_output` is disabled by default to maintain backward compatibility. Enabling this parameter will change the image message encoding from `BGRA8` to `BGR8`, which may affect existing applications that rely on the previous encoding. + +- Enabled SVO support for ZED X One cameras (playback, recording, and diagnostic) +- Set thread names according to the thread function name for easier identification in debuggers and profilers +- Enable SVO for ZedCameraOne + + - add service to pause SVO playback + - add service to set SVO frame ID + - add services to start/stop SVO recording + - publish SVO status + - publish SVO clock on `/clock` topic + +- Publish ZedCameraOne heartbeat status on `~/status/heartbeat` topic + +v5.0.0 +------ +- Backward compatible with SDK v4.2 +- Added official support for ROS 2 Jazzy Jalisco +- Note: requires the latest `zed_msgs` package v5.0.0 +- Added SVO Status topic to monitor the current SVO status of type `zed_msgs::SvoStatus` +- Added fully integrated Health Status topic of type `zed_msgs::HealthStatusStamped` + + - Remove the single health status topics to simplicy health monitoring + +- Remove `cob_srvs` dependency to use the custom `zed_msgs::SetSvoFrame` service +- Added Heartbeat status message at 1 Hz: `~/status/heartbeat` +- Improve performance with the default stereo configuration +- Fix Positional Tracking enabling when required by ZED SDK modules +- Fix realtime IMU data publishing when using SVO2 +- Added parameter 'debug.sdk_verbose_log_file' to Stereo and Mono components to set the path of the SDK verbose log file +- Clean shutdown of ZED components using `pre_shutdown_callback` +- Added new parameter `svo.replay_rate` to set the replay rate for the SVO when not used in realtime mode (range [0.10-5.0]) +- Improved diagnostic information for SVO playback +- Default SVO Recording Compression mode [`0`] is forced to `H265` replacing the old `LOSSLESS` mode + + - H265 is far superior as it uses hardware encoder, resulting in faster, lighter encoding, and dramatically smaller SVO2 files + +- Added `/clock` publisher to be used in SVO Mode to synchronize other nodes with the SVO timestamp +- Added parameter `svo.publish_svo_clock` to enable the `/clock` publisher + + - The parameter 'svo.publish_svo_clock' is normally overridden by the `publish_svo_clock` launch option + +- Moved `brightness`, `contrast`, and `hue` from `common_stereo.yaml` to `zed.yaml`, `zed2.yaml`, `zed2i.yaml`, and `zedm.yaml` files +- Add advanced handling of the Object Detection and Tracking module of the ZED SDK + + - Move the multi-box native object detection parameters to the `object_detection.yaml` file + - Add specific parameters to set the confidence threshold for each of the includes object detection classes of the ZED SDK + - Move the Custom Object Detection parameters to the `custom_object_detection.yaml` file + - Support all the new parameters of the ZED SDK v5 separately for each of the custom object detection classes + +- The usage of the new Object Detection support is fully described on the ZED ROS 2 online documentation: + + - Object Detection: https://docs.stereolabs.com/ros2/object-detection/ + - Custom Object Detection: https://docs.stereolabs.com/ros2/custom-object-detection/ + +- Separated Video/Depth data publishing into its own thread for more precise control over the publishing rate, + independent of the camera grab rate. This enables recording SVO files or processing positional tracking at + full grab rate, while publishing data at a reduced rate to optimize bandwidth usage. +- Added a new launch option 'node_log_type' to set the type of log to be used by the ZED Node. + + - The available options are `screen`, `log`, and `both`. + +- Changed `pos_tracking.area_memory_db_path` to `pos_tracking.area_file_path` to match the ZED SDK parameter name +- Added parameter `pos_tracking.save_area_memory_on_closing` to save the Area Memory before closing the camera +- Fixed Area Mapping file handling according to the ZED SDK policies. + + - The Area Memory file is now saved only if the Area Memory is enabled, if the `pos_tracking.save_area_memory_on_closing` + parameter is set to `true`, if the `pos_tracking.area_file_path` is set and if the `pos_tracking.area_file_path` is valid. + +- Added `save_area_memory` service + + - Set the filename as a parameter. If the filename is empty, it uses the value of the parameter `pos_tracking.area_file_path` if not empty. + +- Added `enable_ipc` launch argument to enable intra-process communication (IPC) when using ROS 2 Composition. + + - Note: NITROS requires IPC to be disabled to work properly. + +- Fixed plane topic names, adding missing node name prefix +- Added camera_info to Confidence Map topic +- Enabled Isaac ROS integration and automatic NITROS usage: https://docs.stereolabs.com/isaac-ros/ + + - Added the parameter `debug.disable_nitros` to disable NITROS usage. This is useful for debugging and testing purposes. + +v4.2.5 +------ +- Add new parameter 'depth.point_cloud_res' to set a specific point cloud publishing resolution + + - 'COMPACT': Standard resolution. Optimizes processing and bandwidth + - 'REDUCED': Half 'COMPACT' resolution. Low processing and low bandwidth requirements + +- Add uptime and frame drop rate information to node diagnostics +- Add image validity check support [SDK 5 required] + + - Add new parameter 'general.enable_image_validity_check' + - Add new topic 'health_status/low_image_quality' to publish image quality status + - Add new topic 'health_status/low_lighting' to publish low light condition status + - Add new topic 'health_status/low_depth_reliability' to publish low depth quality status + - Add new topic 'health_status/low_motion_sensors_reliability' to publish low quality of inertial sensors status + - Set the Node Disgnostic to WARNING if any of the above conditions are detected + +- Add `general.camera_id` parameter to set the camera ID for the ZedCamera. +- Add `general.camera_id` parameter to set the camera ID for the ZedCameraOne. +- Add `camera_id` argument to the `zed_camera.launch.py` launch file. Useful for GMSL2 multi-camera configurations where camera ID is estabilished by the GMSL2 wire. +- Improve Node Diagnostics information +- Add `pos_tracking.reset_pose_with_svo_loop` parameter to reset the camera pose the `initial_base_pose` when the SVO loop is enabled and the SVO playback reaches the end of the file. +- Add `svo.play_from_frame` parameter to set the starting frame when playing an SVO file. +- Add `set_svo_frame` service to set the current frame when playing an SVO file. +- Remove unused open timeout for ZED X One cameras +- Add parameter `svo.use_svo_timestamps` to use the SVO timestamps when publishing data (both stereo and mono components) + +v4.2.x +------ +- Add new `OPTIMIZED` mode for `general.pub_resolution` +- Add new parameter `general.async_image_retrieval` to enable/disable the asynchronous image retrieval to be used with SVO recording. +- Set the Positional Tracking Mode to `GEN_1` as default as wa orkaround for the random crash issue caused by `GEN_2` mode. +- Fixed a bug for raw gray image publisher on Zed One Component: raw gray images were not published when the rectified image topic was subscribed. Thx @Alex-Beh +- Enabled grayscale output for ZED X One cameras (SDK v4.2.3 required) +- Enabled streaming input for ZED X One cameras (SDK v4.2.3 required) +- Fixed wrong range check for the `general.pub_downscale_factor` parameter +- Enhanced sensor thread rate due to an automatically adjusting sleep time +- Removed the `zed-ros2-interfaces` sub-module. The `zed_msgs` package is now included in ROS 2 Humble binaries and can be installed with `sudo apt install ros-humble-zed-msgs`. +- Fixed 4K resolution support for ZED X One 4K cameras +- Changed C++ version to 17 to follow ROS 2 Humble standard +- Renamed `common.yaml` to `common_stereo.yaml` +- Added `common_mono.yaml` for monocular cameras +- Added `video.enable_hdr` to `zedxone4k.yaml` for monocular 4K cameras +- Changed the name of the package `zed_interfaces` to `zed_msgs` to match the ROS 2 naming convention +- Added the new `stereolabs::ZedCameraOne` component to handle ZED X One cameras +- Removed the ZED Wrapper executable node. + + - Modified the launch file to create an isolated composable container that loads the `stereolabs:ZedCamera` or the `stereolabs:ZedCameraOne` component according to the camera model + +- Added support for custom ONNX detection engine (SDK v4.2 required) + + - Added value `CUSTOM_YOLOLIKE_BOX_OBJECTS` to the `object_detection.model` parameter + - Added parameter `object_detection.custom_onnx_file` to set the full path of the custom ONNX file + - Added parameter `object_detection.onnx_input_size` to set the size of the YOLO input tensor + - Added parameter `object_detection.custom_label_yaml` to set the full path to custom YAML file storing class labels in [COCO format](https://docs.ultralytics.com/datasets/detect/coco/#dataset-yaml) + +v4.1.x +------ +- Updated the Docker files to the CUDA 12.4 (PC), L4T 35.4 (Jetson), SDK v4.1.4 +- Added Local Streaming output + + - Added `enable_streaming` service to start/stop a streaming server + - Added Streaming Server diagnostic + - Added parameter 'stream_server.stream_enabled': enable the streaming server when the camera is open + - Added parameter 'stream_server.codec': different encoding types for image streaming + - Added parameter 'stream_server.port': Port used for streaming + - Added parameter 'stream_server.bitrate': Streaming bitrate (in Kbits/s) used for streaming + - Added parameter 'stream_server.gop_size': The GOP size determines the maximum distance between IDR/I-frames + - Added parameter 'stream_server.adaptative_bitrate': Bitrate will be adjusted depending on the number of packets dropped during streaming + - Added parameter 'stream_server.chunk_size': Stream buffers are divided into X number of chunks where each chunk is chunk_size bytes long + - Added parameter 'stream_server.target_framerate': Framerate for the streaming output + +- Added Local Streaming input + + - Added 'stream.stream_address' and 'stream.stream_port' parameter to configure the local streaming input + +- GNSS Fusion temporarily disabled *(available with 4.1.1)* +- Moved parameter 'general.svo_file' to 'svo.svo_path' +- Moved parameter 'general.svo_loop' to 'svo.svo_loop' +- Moved parameter 'general.svo_realtime' to 'svo.svo_realtime' +- Removed obsolete launch files: 'zed.launch.pi','zed2.launch.pi', 'zed2i.launch.pi', 'zedm.launch.pi', 'zedx.launch.pi', 'zedxm.launch.pi' +- Removed obsolete display launch file: 'display_zed.launch.py', 'display_zed2.launch.py', 'display_zed2i.launch.py', 'display_zedm.launch.py', 'display_zedx.launch.py', 'display_zedxm.launch.py' +- Added support for custom virtual stereo cameras made with two calibrated ZED X One cameras *(available with 4.1.1)* +- Added parameter `pos_tracking.reset_odom_with_loop_closure` to automatically reset odometry when a loop closure is detected +- Added new positional tracking information to the `PosTrackStatus` message +- Added new `GnssFusionStatus` message with GNSS Fusion status information *(available with 4.1.1)* +- Added new parameters `gnss_fusion.h_covariance_mul` and `gnss_fusion.v_covariance_mul` to control the effects of the GNSS covariance +- Added support to Automatic ROI + + - Added ROI diagnostic + - Added parameter `debug.debug_roi` + - Publish ROI mask image on the topic `~/roi_mask` using image transport + - Moved the parameter `general.region_of_interest` to `region_of_interest.manual_polygon` + - Added automatic Region of Interest support + - Added parameter `region_of_interest.automatic_roi` + - Added parameter `region_of_interest.depth_far_threshold_meters` + - Added parameter `region_of_interest.image_height_ratio_cutoff` + - Added parameter `region_of_interest.apply_to_depth` + - Added parameter `region_of_interest.apply_to_positional_tracking` + - Added parameter `region_of_interest.apply_to_object_detection` + - Added parameter `region_of_interest.apply_to_body_tracking` + - Added parameter `region_of_interest.apply_to_spatial_mapping` + +- Removed QoS parameters to use ROS 2 QoS overwrite -> https://design.ros2.org/articles/qos_configurability.html +- Added support for new `NEURAL_PLUS` depth mode +- Added new `_gnss_link` frame to URDF to set the position of the GNSS antenna with respect to the camera position +- New Docker configuration files allow to easily create "ZED ROS2 Wrapper" images based on specific tag versions. [Read more](./docker/README.md) +- Fixed a bug while playing a ZED X stream on a "not-Jetson" host device +- Add support for point cloud transport [only Humble, no Foxy] +- Add support for FFMPEG image transport +- Add new `ffmpeg.yaml` configuration file +- Fix `~/imu/data_raw` message not containing RAW IMU data + +v4.0.8 +------ +- The parameter `general.sdk_verbose` has been moved to `debug.sdk_verbose` and set to `0` as default. +- Added new parameter `general.optional_opencv_calibration_file` to use custom OpenCV camera calibrations. +- Added [new tutorial](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_robot_integration) to illustrate how to integrate one or more ZED cameras on a robot +- Added 'simulation.sim_enabled' parameter to enable the simulation mode +- Added 'simulation.sim_address' parameter to set the simulation server address +- Added 'simulation.sim_port' parameter to set the simulation server port +- Added `/clock` subscriber to check the presence of the required message when `use_sim_time` is true +- Force `grab_frame_rate` and `pub_frame_rate` to 60 Hz in simulation +- Force `grab_resolution` to `HD1080` in simulation +- Removed the `general.zed_id` parameter. Always use `general.serial_number` to distinguish between different cameras in a multi-camera configuration. +- The multi-camera example has been updated to match the new TF configuration +- The old launch files are now obsolete: 'ros2 launch zed_wrapper .launch.py' is replaced by 'ros2 + launch zed_wrapper zed_camera.launch.py camera_model:=' +- The reference link for positional tracking is no longer 'base_link' but `_camera_link`. + This will allow an easier ZED integration in existing robot configuration because the transform `base_link` -> `camera_link` + is no longer published by the ZED ROS2 Wrapper. Thanks to @SteveMacenski for the advice + + - Removed `parent` and `origin` parameters from `zed_macro.urdf.xacro` + - Removed launch argument `cam_pose` from `zed_camera.launch.py` + +- Moved parameter `publish_imu_tf` from `pos_tracking` to `sensors` to make it available also in "no depth" configurations of the node +- Added new parameter `pos_tracking.pos_tracking_mode` to exploit the new ZED SDK `QUALITY` mode for improved odometry and localization +- New Video/Depth processing throttling method by using the `grab_compute_capping_fps` ZED SDK parameter instead of a dedicated thread +- Advanced parameters to handle Thread scheduling policy and priorities (sudo required):`thread_sched_policy`,`thread_grab_priority`, + `thread_sensor_priority`,`thread_pointcloud_priority` +- Added new GNSS calibration parameters: `enable_reinitialization`, `enable_rolling_calibration`, `enable_translation_uncertainty_target`, `gnss_vio_reinit_threshold`, `target_translation_uncertainty`, `target_yaw_uncertainty` +- Added new Plane Detection parameters: `pd_max_distance_threshold`, `pd_normal_similarity_threshold` + +v4.0.5 +---------- +- The parameter `general.pub_resolution` can now take only `NATIVE` and `CUSTOM` values. 'NATIVE' to use the same `general.grab_resolution` - `CUSTOM` to apply the `general.pub_downscale_factor` downscale factory to reduce bandwidth in transmission +- Added new parameter `general.pub_downscale_factor` to be used with the new option `CUSTOM` for the parameter `general.pub_resolution` +- `ULTRA` is the new default value for `depth.depth_mode` (better performance for odometry and positional tracking) +- Added resolution `HD1080` for ZED X +- Fix issue with Body Tracking start/stop by service call. Now Body Tracking can be restarted multiple times +- Fix depth grab performance by removing a [not required `PNG Write` call](https://github.com/stereolabs/zed-ros2-wrapper/pull/164). Thank you Esteban Zamora @ezamoraa +- Fix bug with `general.pub_resolution` value, not allowing to select the correct data publish resolution +- Added new launch parameter `ros_params_override_path` to provide the path to a custom YAML file to override the parameters of the ZED Node without modifying the original files in the `zed_wrapper/config` folder. Thank you David Lu @MetroRobots + +v4.0.0 +------ +- Added support for ZED-X and ZED-X Mini + + - Moved `general.grab_resolution` and `general.grab_frame_rate` to the yaml file specific for the relative camera model (i.e. `zed.yaml`, `zedm.yaml`, `zed2.yaml`, `zed2i.yaml`, `zedx.yaml`, `zedxm.yaml`) + + - Added `zedx.launch.py` for ZED-X + - Added `zedxm.launch.py` for ZED-X Mini + - Improve `zed_macro.urdf.xacro` with specific configuration for the new camera models + - Added `display_zedx.launch.py` for ZED-X to ZED-ROS2-Examples + - Added `display_zedxm.launch.py` for ZED-X Mini to ZED-ROS2-Examples + - Added ZED-X and ZED-X Mini STL files to ZED-ROS2-Interfaces + +- Positional Tracking + + - Added `pos_tracking.set_as_static` parameters for applications with a static camera monitoring a robotics environment. See [PR #122](https://github.com/stereolabs/zed-ros2-wrapper/pull/122 ) Thx @gabor-kovacs + - Added custom message type `PosTrackStatus` + - Publish message on topic `~/pose/status` with the current status of the pose from the ZED SDK + - Publish message on topic `~/odom/status` with the current status of the odometry from the ZED SDK + +- Body Tracking + + - Added Support for the new Body Tracking module + - Added parameter `body_tracking.bt_enabled` to enable Body Tracking + - Added parameter `body_tracking.model` to set the AI model to be used + - Added parameter `body_tracking.body_format` to set the Body Format to be used + - Added parameter `body_tracking.allow_reduced_precision_inference` to improve performances + - Added parameter `body_tracking.max_range` to set the max range for Body Detection + - Added parameter `body_tracking.body_kp_selection` to choose the Body key points to be used + - Added parameter `body_tracking.enable_body_fitting` to enable body fitting + - Added parameter `body_tracking.enable_tracking` to enable the tracking of the detected bodies + - Added parameter `body_tracking.prediction_timeout_s` to set the timeout of the prediction phase while tracking + - Added parameter `body_tracking.confidence_threshold` to set the detection confidence threshold + - Added parameter `body_tracking.minimum_keypoints_threshold` to set the minimum number of detected key points to consider a body valid + - Publish new message on topic `~/body_trk/skeletons` + - Added service `enable_body_trk` to start/stop body tracking + +- GNSS fusion integration + + - New param `gnss_fusion.gnss_fusion_enabled` to enable GNSS fusion + - New param `gnss_fusion.gnss_fix_topic` name of the topic containing GNSS Fix data of type `sensor_msgs/NavSatFix` + - Added `nmea_msgs` dependency + - Added GNSS Fix Diagnostic + - Added new launch parameter `gnss_frame` to enable the GNSS link in the ZED URDF + - Added new node parameter `gnss_fusion.gnss_zero_altitude` to ignore GNSS altitude information + - Added new node parameter `gnss_fusion.gnss_frame` to set the name of the frame link of the GNSS sensor + - Disable Area Memory (loop closure) when GNSS fusion is enabled + - Added services `toLL` and `fromLL` to use the ZED ROS2 Wrapper with the Nav2 Waypoint Navigation package + - Added `geographic_msgs::msg::GeoPoseStamped` message publisher + - Added parameter `gnss_fusion.publish_utm_tf` + - Added parameter `gnss_fusion.broadcast_utm_transform_as_parent_frame` + - Added parameter `gnss_fusion.gnss_init_distance` + - Publish message on topic `~/geo_pose/status` with the current status of the GeoPose from the ZED SDK + - Publish message on topic `~/pose/filtered` with the current GNSS filtered pose in `map` frame + - Publish message on topic `~/pose/filtered/status` with the current status of the GNSS filtered pose from the ZED SDK + +- Object Detection + + - Added `object_detection.allow_reduced_precision_inference` to allow inference to run at a lower precision to improve runtime and memory usage + - Added `object_detection.max_range` to defines a upper depth range for detections + - Removed `object_detection.body_format` + +- Docker + + - Added Docker files (see `docker` folder) ready to create Docker images for desktop host devices + +- Examples/Tutorials + + - Added multi-camera example in `zed-ros2-examples` repository. + +- Added full Terrain Mapping (local obstacle detection) support [EXPERIMENTAL FEATURE AVAILABLE ONLY FOR BETA TESTERS] + + - ZED SDK Terrain Mapping published as GridMap message + - Added parameter `local_mapping.terrain_mapping_enabled` to enable terrain mapping publishing a local obstacle map + - Added parameter `local_mapping.data_pub_rate` to set the Local Map data publish frequency + - Added parameter `local_mapping.grid_resolution` to set the Local Map resolution in meters [min: 0.01 - max: 1.0] + - Added parameter `local_mapping.grid_range` to set the maximum depth range for local map generation [min: 1.0 - max: 8.0] + - Added parameter `local_mapping.height_threshold` to set the maximum height for obstacles + - Publish gridmap on topic `local_map/gridmap` + - Publish elevation map image on topic `local_map/elev_img` + - Publish obstacle color map image on topic `local_map/col_img` + - Added traversability cost computation for Terrain Mapping (local_mapping) + + - Change parameter `local_mapping.height_threshold` to `local_mapping.robot_heigth` + - Added parameter `local_mapping.robot_radius` to set radius of the robot + - Added parameter `local_mapping.robot_max_step` to set max height of a step that the robot can overcome + - Added parameter `local_mapping.robot_max_slope` to set max slope (degrees) that the robot can overcome + - Added parameter `local_mapping.robot_max_roughness` to set max roughness of the terrain that the robot can overcome + +- Added support for simulated data [EXPERIMENTAL FEATURE AVAILABLE ONLY FOR BETA TESTERS] + + - Added parameter `use_sim_time` to enable SIMULATION mode + - Added parameter `sim_address` tos set the local address of the machine running the simulator + - Change StopWatch to use ROS clock instead of System Clock. In this way diagnostic and time checking work also in simulation + - Disable camera settings control in simulation + +- Others + + - Removed `sensing_mode`, no more available in SDK v4.0 + - Removed `extrinsic_in_camera_frame`, no more available in SDK v4.0 + - Added `zed_id` and `serial_number` launch parameters to open the correct camera in multi-camera configurations. + - Code lint and re-formatting according to [ROS2 code rules](https://docs.ros.org/en/humble/The-ROS2-Project/Contributing/Code-Style-Language-Versions.html). + - Added support for automatic lint tools to all the packages. + - Removed node parameter `general.resolution`, replaced by `general.grab_resolution`. + - Added node parameter `general.pub_resolution` used to reduce node computation and message bandwidth. + + - Available output resolutions: `HD2K`, `HD1080`, `HD720`, `MEDIUM`, `VGA`. `MEDIUM` is an optimized output resolution to maximize throughput and minimize processing costs. + + - Removed node parameters `video.img_downsample_factor` and `depth.depth_downsample_factor`. Use the new parameter `general.pub_resolution` instead. + - Change `general.grab_resolution` and `general.pub_resolution` from integer to string. + - Added new `LOW` value for `general.pub_resolution` (half the `MEDIUM` output resolution). + - Removed `depth.quality` parameter (replaced with `depth.depth_mode`) + - Added `depth.depth_mode` parameter: a string reflecting the ZED SDK `DEPTH_MODE` available value names + - The parameter `depth.depth_stabilization` is now an integer in [0,100] reflecting ZED SDK behavior + - Fix distortion model (see Issue [#128](https://github.com/stereolabs/zed-ros2-wrapper/issues/128)) + - Improve the code for Moving Average calculation for better node diagnostics. + - Temperature diagnostic is now always updated even if `sensors.sensors_image_sync` is true and no image topics are subscribed. + - Improve Grab thread and Video/Depth publishing thread elaboration time diagnostic. + - Added a check on timestamp to not publish already published point cloud messages in the point cloud thread + - Improve thread synchronization when the frequency of the `grab` SDK function is minor of the expected camera frame rate setting because of a leaking of elaboration power. + - Added diagnostic warning if the frequency of the camera grabbing thread is minor than the selected `general.grab_frame_rate` value. + - Removed annoying build log messages. Only warning regarding unsupported ROS 2 distributions will be displayed when required. + - Convert `shared_ptr` to `unique_ptr` for IPC support + - Improve the `zed_camera.launch.py` + + - Added support for `OpaqueFunction` in order to automatically configure the launch file according to the value of the launch parameter `cam_model`. + - Change parameters to set camera pose in launch files. From 6 separated parameters (`cam_pos_x`,`cam_pos_y`,`cam_pos_z`,`cam_roll`,`cam_pitch`,`cam_yaw`) to one single array (`cam_pose`). + - Removed the workaround for empty `svo_path` launch parameter values thanks to `TextSubstitution`. + - Modify the "display" launch files in [zed-ros2-examples](https://github.com/stereolabs/zed-ros2-examples) to match the new configuration. + - Added `publish_tf` and `publish_map_tf` launch parameters useful for multi-camera configuretion or external odometry fusion. + + - Change LICENSE to Apache 2.0 to match ROS 2 license. + +v3.8.x +------ +- Fixed `set_pose` wrong behavior. Now initial odometry is coherent with the new starting point. +- Added Plane Detection. +- Fixed "NO DEPTH" mode. By setting `depth/quality` to `0` now the depth extraction and all the sub-modules depending on it are correctly disabled. +- Added `debug` sub-set of parameters with new parameters `debug_mode` and `debug_sensors`. +- Added support for ROS 2 Humble. Thx @nakai-omer. + The two ROS 2 LTS releases are now supported simoultaneously. +- Set `read_only` flag in parameter descriptors for non-dynamic parameters. Thx @bjsowa. +- Enabled Intra Process Communication. The ZED node no longer publishes topics with `TRANSIENT LOCAL` durability. +- Improved TF broadcasting at grabbing frequency +- Improved IMU/Left Camera TF broadcasting at IMU frequency +- Fixed data grabbing frame rate when publishing is set to a lower value +- Added TF broadcasting diagnostic +- The parameter `general.sdk_verbose` is now an integer accepting different SDK verbose levels. +- Moved Object Detection parameters from cameras configuration files to `common.yaml` +- Moved Sensor Parameters from cameras configuration files to `common.yaml` +- New data thread configuration to maximize data publishing frequency + + - Sensor data publishing moved from timer to thread + - RGB/Depth data publishing moved from timer to thread + +- Fixed random errors when closing the node +- Fixed wrong timing when playing SVO in `real-time` mode +- Fixed units for atmospheric pressure data. Now pressure is published in `Pascals` according to the [definition of the topic](https://github.com/ros2/common_interfaces/blob/humble/sensor_msgs/msg/FluidPressure.msg). +- Added new parameter `pos_tracking.transform_time_offset` to fix odometry TF timestamp issues +- Added new parameter `pos_tracking.depth_min_range` for removing fixed zones of the robot in the FoV of the camerafrom the visual odometry evaluation +- Added new parameter `pos_tracking.sensor_world` to define the world type that the SDK can use to initialize the Positionnal Tracking module +- Added new parameter `object_detection.prediction_timeout` for setting the timeout time [sec] of object prediction when not detected. +- Added support for ZED SDK Regiorn of Interest: + + - Added parameter `general.region_of_interest` to set the region of interest for SDK processing. + - Added the service `resetRoi` to reset the region of interest. + - Added the service `setRoi` to set a new region of interest. + +v3.7.x +---------- +- Added support for sport-related OD objects +- Added `remove_saturated_areas` dynamic parameter to disable depth filtering when luminance >=255 +- Added `sl::ObjectDetectionParameters::filtering_mode` parameter +- Publish `depth_info` topic with current min/max depth information +- Fix parameter override problem (Issue #71). Thx @kevinanschau +- Added default xacro path value in `zed_camera.launch.py`. Thx @sttobia +- Fix `zed-ros2-interfaces` sub-module url, changing from `ssh` to `https`. + +v3.6.x (2021-12-03) +------------------- +- Moved the `zed_interfaces` package to the `zed-ros2-interfaces` repository to match the same configuration of the ROS1 wrapper +- The `zed-ros2-interfaces` repository has been added as a sub-module to this repository +- Added new _base_link frame on the base of the camera to easily handle camera positioning on robots. Thx @civerachb-cpr +- Improve URDF by adding 3° slope for ZED and ZED2, X-offset for optical frames to correctly match the CMOS sensors position on the PCB, X-offset for mounting screw on ZED2i +- Added `zed_macro.urdf.xacro` to be included by other xacro file to easily integrate ZED cameras in the robot descriptions. See ROS1 PR [#771](https://github.com/stereolabs/zed-ros-wrapper/pull/771) for details. Thx @civerachb-cpr +- Fix URDF `height` value for ZED, ZED2 and ZED2i +- Fix performances drop on slower platforms. Thx @roncapat +- Fix SVO LOOP wrong behavior. Thx @kevinanschau +- Added xacro support for automatic URDF configuration +- Reworked launch files to support xacro and launch parameters + + - Use `ros2 launch zed_wrapper -s` to retrieve all the available parameters + +- Added `svo_path:=` as input for all the launch files to start the node using an SVO as input without modifying 'common.yaml` +- Improved diagnostic information adding elaboration time on all the main tasks +- Improved diagnostic time and frequencies calculation +- Added StopWatch to sl_tools +- Enabled Diagnostic status publishing +- Changed the default values of the QoS parameter reliability for all topics from BEST_EFFORT to RELIABLE to guarantee compatibility with all ROS 2 tools +- Fixed tab error in `zedm.yaml` +- Fixed compatibility issue with ZED SDK older than v3.5 - Thanks @PhilippPolterauer +- Migration to ROS 2 Foxy Fitzroy + +v3.5.x (2021-07-05) +------------------- +- Added support for SDK v3.5 +- Added support for the new ZED 2i +- Added new parameter `pos_tracking/pos_tracking_enabled` to enable positional tracking from start even if not required by any subscribed topic. This is useful, for example, to keep the TF always updated. +- Added support for new AI models: `MULTI_CLASS_BOX_MEDIUM` and `HUMAN_BODY_MEDIUM` +- Depth advertising is disabled when depth is disabled (see `sl::DETH_MODE::NONE`) diff --git a/src/lib/zed-ros2-wrapper/CONTRIBUTING.md b/src/lib/zed-ros2-wrapper/CONTRIBUTING.md new file mode 100644 index 0000000000..6ddd6877b6 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/CONTRIBUTING.md @@ -0,0 +1,50 @@ + +## Submitting your code changes + +Code contributions should be made via pull requests to the appropriate repositories: +* [zed-ros2-wrapper](https://github.com/stereolabs/zed-ros2-wrapper/pulls) +* [zed-ros2-interfaces](https://github.com/stereolabs/zed-ros2-interfaces/pulls) +* [zed-ros2-examples](https://github.com/stereolabs/zed-ros2-examples/pulls) + +We ask all contributors to follow the practices explained in [ROS 2 documentation](https://docs.ros.org/en/humble/The-ROS2-Project/Contributing/Code-Style-Language-Versions.html). + +Before submitting a pull request please perform this list of tasks from the root of your ROS 2 workspace: +1. Automatic code formatting: + + `$ ament_uncrustify --reformat src` + +2. Build the packages to check for compile errors: + + `$ colcon build --symlink-install --cmake-args=-DCMAKE_BUILD_TYPE=Release` + +3. Perform the automatic build tests: + + `$ colcon test` + +4. Analyze and solve eventually reported errors: + + `$ colcon test-result --verbose` + +5. Repeat steps (1) -> (4) until all reported formatting errors have been resolved. + + +## License + +Any contribution that you make to this repository will +be under the Apache 2 License, as dictated by that +[license](http://www.apache.org/licenses/LICENSE-2.0.html): + +~~~ +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +~~~ + +Contributors must sign-off each commit by adding a `Signed-off-by: ...` +line to commit messages to certify that they have the right to submit +the code they are contributing to the project according to the +[Developer Certificate of Origin (DCO)](https://developercertificate.org/). \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/LICENSE b/src/lib/zed-ros2-wrapper/LICENSE new file mode 100644 index 0000000000..ae79ff6643 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/LICENSE @@ -0,0 +1,251 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +## Some of TensorFlow's code is derived from Caffe, which is subject to the following copyright notice: + +COPYRIGHT + +All contributions by the University of California: + +Copyright (c) 2014, The Regents of the University of California (Regents) +All rights reserved. + +All other contributions: + +Copyright (c) 2014, the respective contributors +All rights reserved. + +Caffe uses a shared copyright model: each contributor holds copyright over +their contributions to Caffe. The project versioning records all such +contribution and copyright details. If a contributor wants to further mark +their specific copyright on a particular contribution, they should indicate +their copyright solely in the commit message of the change when it is +committed. + +LICENSE + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +CONTRIBUTION AGREEMENT + +By contributing to the BVLC/caffe repository through pull-request, comment, +or otherwise, the contributor releases their content to the +license and copyright terms herein. diff --git a/src/lib/zed-ros2-wrapper/README.md b/src/lib/zed-ros2-wrapper/README.md new file mode 100644 index 0000000000..e83d205537 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/README.md @@ -0,0 +1,330 @@ +

+ Stereolabs
+ ROS 2 wrapper +

+ +

+ ROS 2 packages for using Stereolabs ZED Camera cameras.
+ ROS 2 Foxy Fitzroy (Ubuntu 20.04) - ROS 2 Humble Hawksbill (Ubuntu 22.04) - ROS 2 Jazzy Jalisco (Ubuntu 24.04) +

+ +
+ +This package enables the use of ZED cameras with ROS 2, providing access to a variety of data types, including: + +- Color and grayscale images, both rectified and unrectified +- Depth data +- Colored 3D point clouds +- Position and mapping, with optional GNSS data fusion +- Sensor data +- Detected objects +- Human skeleton data +- And more... + +[More information](https://www.stereolabs.com/docs/ros2) + +![Point_cloud](./images/PointCloud_Depth_ROS.jpg) + +## Installation + +### Prerequisites + +- [Ubuntu 20.04 (Focal Fossa)](https://releases.ubuntu.com/focal/), [Ubuntu 22.04 (Jammy Jellyfish)](https://releases.ubuntu.com/jammy/), or [Ubuntu 24.04 (Noble Numbat)](https://releases.ubuntu.com/noble/) +- [ZED SDK](https://www.stereolabs.com/developers/release/latest/) v5.2 (to support older versions please check the [releases](https://github.com/stereolabs/zed-ros2-wrapper/releases)) +- [CUDA](https://developer.nvidia.com/cuda-downloads) dependency +- ROS 2 Foxy Fitzroy (deprecated), ROS 2 Humble Hawksbill, or ROS 2 Jazzy Jalisco: + - [Foxy on Ubuntu 20.04](https://docs.ros.org/en/foxy/Installation/Linux-Install-Debians.html) [**Not recommended. EOL reached**] + - [Humble on Ubuntu 22.04](https://docs.ros.org/en/humble/Installation/Linux-Install-Debians.html) [EOL May 2027] + - [Jazzy Jalisco on Ubuntu 24.04](https://docs.ros.org/en/jazzy/Installation/Linux-Install-Debians.html) [EOL May 2029] + +### Build the package + +The **zed_ros2_wrapper** is a [colcon](http://design.ros2.org/articles/build_tool.html) package. + +> :pushpin: **Note:** If you haven’t set up your colcon workspace yet, please follow this short [tutorial](https://index.ros.org/doc/ros2/Tutorials/Colcon-Tutorial/). + +To install the **zed_ros2_wrapper**, open a bash terminal, clone the package from GitHub, and build it: + +```bash +mkdir -p ~/ros2_ws/src/ # create your workspace if it does not exist +cd ~/ros2_ws/src/ #use your current ros2 workspace folder +git clone https://github.com/stereolabs/zed-ros2-wrapper.git +cd .. +sudo apt update +rosdep update +rosdep install --from-paths src --ignore-src -r -y # install dependencies +colcon build --symlink-install --cmake-args=-DCMAKE_BUILD_TYPE=Release --parallel-workers $(nproc) # build the workspace +echo source $(pwd)/install/local_setup.bash >> ~/.bashrc # automatically source the installation in every new bash (optional) +source ~/.bashrc +``` + +> :pushpin: **Note:** the dependency `zed_msgs` is no longer installed as a submodule of this package; it is available through `apt` as a binary package with ROS 2 Humble. When working with ROS 2 Foxy, or other distributions, you can install it from the sources from the [zed-ros2-interfaces repository](https://github.com/stereolabs/zed-ros2-interfaces?tab=readme-ov-file#install-the-package-from-the-source-code). + +> :pushpin: **Note:** If `rosdep` is missing, you can install it with: +> +>`sudo apt-get install python3-rosdep python3-rosinstall-generator python3-vcstool python3-rosinstall build-essential` + +> :pushpin: **Note:** The `zed_debug` package is intended for internal development only. If you don’t need it, you can skip building this package by adding `--packages-skip zed_debug` to your `colcon` command. + +> :pushpin: **Note:** When using the ZED ROS 2 Wrapper on an NVIDIA Jetson with JP6, you may get the following error when building the package for the first time +> +> ```bash +> CMake Error at /usr/share/cmake-3.22/Modules/FindCUDA.cmake:859 (message): +> Specify CUDA_TOOLKIT_ROOT_DIR +> Call Stack (most recent call first): +> /usr/local/zed/zed-config.cmake:72 (find_package) +> CMakeLists.txt:81 (find_package) +> ``` +> +> You can fix the problem by installing the missing `nvidia-jetpack` packages: +> +> `sudo apt install nvidia-jetpack nvidia-jetpack-dev` +> +> :pushpin: **Note:** The option `--symlink-install` is very important, it allows the use of symlinks instead of copying files to the ROS 2 folders during the installation, where possible. Each package in ROS 2 must be installed, and all the files used by the nodes must be copied into the installation folders. Using symlinks allows you to modify them in your workspace, reflecting the modification during the next executions without issuing a new `colcon build` command. This is true only for all the files that don't need to be compiled (Python scripts, configurations, etc.). +> +> :pushpin: **Note:** If you are using a different console interface like zsh, you have to change the `source` command as follows: `echo source $(pwd)/install/local_setup.zsh >> ~/.zshrc` and `source ~/.zshrc`. + +## Starting the ZED node + +> :pushpin: **Note:** we recommend reading [this ROS 2 tuning guide](https://www.stereolabs.com/docs/ros2/dds_and_network_tuning) to improve the ROS 2 experience with ZED. + +To start the ZED node, open a bash terminal and use the [CLI](https://index.ros.org/doc/ros2/Tutorials/Introspection-with-command-line-tools/) command `ros2 launch`: + +```bash +ros2 launch zed_wrapper zed_camera.launch.py camera_model:= +``` + +Replace `` with the model of the camera that you are using: `'zed'`, `'zedm'`, `'zed2'`, `'zed2i'`, `'zedx'`, `'zedxm'`, `'zedxhdrmini'`, `'zedxhdr'`, `'zedxhdrmax'`, `'virtual'`,`'zedxonegs'`,`'zedxone4k'`,`'zedxonehdr'`. + +The `zed_camera.launch.py` is a Python launch script that automatically starts the ZED node using ["manual composition"](https://index.ros.org/doc/ros2/Tutorials/Composition/). The parameters for the indicated camera model are loaded from the relative "YAML files." +A Robot State Publisher node is started to publish the camera static links and joints loaded from the URDF model associated with the camera model. + +> :pushpin: **Note:** You can set your configurations by modifying the parameters in the files **common_stereo.yaml**, **zed.yaml** **zedm.yaml**, **zed2.yaml**, **zed2i.yaml**, **zedx.yaml**, **zedxm.yaml**, **common_mono.yaml**, **zedxonegs.yaml**, **zedxone4k.yaml**, **zedxonehdr.yaml** available in the folder `zed_wrapper/config`. + +You can get the list of all the available launch parameters by using the `-s` launch option: + +```bash +ros2 launch zed_wrapper zed_camera.launch.py -s +ros2 launch zed_display_rviz2 display_zed_cam.launch.py -s +``` + +For full descriptions of each parameter, follow the complete guide [here](https://www.stereolabs.com/docs/ros2/zed_node#configuration-parameters). + +### RViz visualization + +To start a pre-configured RViz environment and visualize the data of all ZED cameras, we provide in the [`zed-ros2-examples` repository](https://github.com/stereolabs/zed-ros2-examples/tree/master/zed_display_rviz2). You'll see more advanced examples and visualizations that demonstrate depth, point clouds, odometry, object detection, etc. + +You can also quickly check that your depth data is correctly retrieved in RViz with `rviz2 -d ./zed_wrapper/config/rviz2/.rviz`. RViz subscribes to numerous ROS topics, which can potentially impact the performance of your application compared to when it runs without RViz. + +### Simulation mode + +> :pushpin: **Note:** This feature is incompatible with the ZED X One and the older first-generation ZED cameras. + +Launch a standalone ZED ROS 2 node with simulated ZED data as input by using the following command: + +```bash +ros2 launch zed_wrapper zed_camera.launch.py camera_model:=zedx sim_mode:=true +``` + +Launch options: + +- [Mandatory] `camera_model`: indicates the model of the simulated camera. It's required that this parameter match the model of the simulated camera. In most cases, it will be a ZED X, since the first versions of the simulation plugins that we released are simulating this type of device. +- [Mandatory] `sim_mode`: start the ZED node in simulation mode if `true`. +- [Optional] `use_sim_time`: force the node to wait for valid messages on the topic `/clock`, and so use the simulation clock as the time reference. +- [Optional] `sim_address`: set the address of the simulation server. The default is `127.0.0.1`, and it's valid if the node runs on the same machine as the simulator. +- [Optional] `sim_port`: set the port of the simulation server. It must match the value of the field `Streaming Port` of the properties of the `ZED camera streamer` Action Graph node. A different `Streaming Port` value for each camera is required in multi-camera simulations. + +You can also start a preconfigured instance of `rviz2` to visualize all the information available in the simulation by using the command: + +```bash +ros2 launch zed_display_rviz2 display_zed_cam.launch.py camera_model:=zedx sim_mode:=true +``` + +The `display_zed_cam.launch.py` launch file includes the `zed_camera.launch.py` launch file, hence it gets the same parameters. + +Here's an example of `rviz2` running with the simulated information obtained by placing the ZED camera on a shelf of a simulated warehouse: + +![Sim RVIZ2](./images/sim_rviz.jpg) + +![Shelves](./images/zed_shelves.jpg) + +Supported simulation environments: + +- [NVIDIA Omniverse Isaac Sim](https://www.stereolabs.com/docs/isaac-sim/) + +## More features + +### Point Cloud Transport + +The ZED ROS 2 Wrapper supports [Point Cloud Transport](http://wiki.ros.org/point_cloud_transport) to publish point clouds using different compression methods. + +This feature is available only if the package `point_cloud_transport` is installed in your ROS 2 environment; otherwise, it will be disabled automatically. + +To install the packages, use the command: + +```bash +sudo apt install ros-$ROS_DISTRO-point-cloud-transport ros-$ROS_DISTRO-point-cloud-transport-plugins +``` + +:pushpin: **Note:** We removed the `point_cloud_transport` package as a required dependency of the ZED ROS 2 Wrapper to avoid forcing its installation in all the environments where the ZED ROS2 Wrapper is used. If you want to use this feature, you must install the package manually. + +### SVO recording + +[SVO recording](https://www.stereolabs.com/docs/video/recording/) can be started and stopped while the ZED node is running using the service `start_svo_recording` and the service `stop_svo_recording`. +[More information](https://www.stereolabs.com/docs/ros2/zed_node/#services) + +### Object Detection + +> :pushpin: **Note:** This feature is incompatible with the ZED X One and the older first-generation ZED cameras. + +Object Detection can be enabled *automatically* when the node starts by setting the parameter `object_detection/od_enabled` to `true` in the file `common_stereo.yaml`. +The Object Detection can be enabled/disabled *manually* by calling the services `enable_obj_det`. + +You can find a detailed explanation of the Object Detection module in the [ZED ROS 2 documentation](https://www.stereolabs.com/docs/ros2/object-detection). + +### Custom Object Detection with YOLO-like ONNX model file + +> :pushpin: **Note:** This feature is incompatible with the ZED X One and the older first-generation ZED cameras. + +Object Detection inference can be performed using a **custom inference engine** in YOLO-like ONNX format. + +You can generate your ONNX model by using Ultralytics YOLO tools. + +Install Ultralytics YOLO tools: + +```bash +python -m pip install ultralytics +``` + +If you have already installed the `ultralytics` package, we recommend updating it to the latest version: + +```bash +pip install -U ultralytics +``` + +Export an ONNX file from a YOLO model (more info [here](https://docs.ultralytics.com/modes/export/)), for example: + +```bash +yolo export model=yolo11n.pt format=onnx simplify=True dynamic=False imgsz=640 +``` + +For a custom-trained YOLO model, the weight file can be changed, for example: + +```bash +yolo export model=yolov8l_custom_model.pt format=onnx simplify=True dynamic=False imgsz=512 +``` + +Please refer to the [Ultralytics documentation](https://github.com/ultralytics/ultralytics) for details. + +Modify the `common_stereo.yaml` parameters to match your configuration: + +- Set `object_detection.model` to `CUSTOM_YOLOLIKE_BOX_OBJECTS` + +Modify the `custom_object_detection.yaml` parameters to match your configuration. + +> :pushpin: **Note:** The first time the custom model is used, the ZED SDK optimizes it to get the best performance from the GPU installed on the host. Please wait for the optimization to complete. When using Docker, we recommend using a shared volume to store the optimized file on the host and perform the optimization only once. + +Console log while optimization is running: + +```bash +[zed_wrapper-3] [INFO] [1729184874.634985183] [zed.zed_node]: === Starting Object Detection === +[zed_wrapper-3] [2024-10-17 17:07:55 UTC][ZED][INFO] Please wait while the AI model is being optimized for your graphics card +[zed_wrapper-3] This operation will be run only once and may take a few minutes +``` + +You can find a detailed explanation of the Custom Object Detection module in the [ZED ROS 2 documentation](https://www.stereolabs.com/docs/ros2/custom-object-detection). + +### Body Tracking + +> :pushpin: **Note:** This feature is incompatible with the ZED X One and the older first-generation ZED cameras. + +The Body Tracking can be enabled *automatically* when the node starts by setting the parameter `body_tracking/bt_enabled` to `true` in the file `common_stereo.yaml`. + +### Spatial Mapping + +> :pushpin: **Note:** This feature is incompatible with the ZED X One camera. + +The Spatial Mapping can be enabled automatically when the node starts setting the parameter `mapping/mapping_enabled` to `true` in the file `common_stereo.yaml`. +The Spatial Mapping can be enabled/disabled manually by calling the service `enable_mapping`. + +### GNSS fusion + +> :pushpin: **Note:** This feature is incompatible with the ZED X One camera. + +The ZED ROS 2 Wrapper can subscribe to a `NavSatFix` topic and fuse GNSS data information +with Positional Tracking information to obtain a precise robot localization referred to Earth coordinates. +To enable GNSS fusion, set the parameter `gnss_fusion.gnss_fusion_enabled` to `true`. +You must set the correct `gnss_frame` parameter when launching the node, e.g., `gnss_frame:='gnss_link'`. +The services `toLL` and `fromLL` can be used to convert Latitude/Longitude coordinates to robot `map` coordinates. + +### 2D mode + +> :pushpin: **Note:** This feature is incompatible with the ZED X One camera. + +For robots moving on a planar surface, activating the "2D mode" (parameter `pos_tracking/two_d_mode` in `common_stereo.yaml`) is possible. +The value of the coordinate Z for odometry and pose will have a fixed value (parameter `pos_tracking/fixed_z_value` in `common_stereo.yaml`). +Roll, Pitch, and the relative velocities will be fixed to zero. + +## NVIDIA® Isaac ROS integration + +The ZED ROS 2 Wrapper is compatible with the [NVIDIA® Isaac ROS](https://nvidia-isaac-ros.github.io/) framework, which provides a set of tools and libraries for building robotics applications on NVIDIA® platforms. + +The ZED ROS 2 Wrapper leverages [NITROS](https://nvidia-isaac-ros.github.io/concepts/nitros/index.html) (NVIDIA® Isaac Transport for ROS) a technology to enable data streaming through NVIDIA-accelerated ROS graphs. + +![NITROS communication](./images/nitros-graph.gif) + +Read the full [Isaac ROS integration guide](https://docs.stereolabs.com/isaac-ros/) and learn how to set up your development environment to use the ZED ROS2 Wrapper with Isaac ROS and NITROS. + +## Examples and Tutorials + +Examples and tutorials are provided to better understand how to use the ZED wrapper and how to integrate it into the ROS 2 framework. +See the [`zed-ros2-examples` repository](https://github.com/stereolabs/zed-ros2-examples) + +### RVIZ2 visualization examples + +- Example launch files to start a preconfigured instance of RViz displaying all the ZED Wrapper node information: [zed_display_rviz2](https://github.com/stereolabs/zed-ros2-examples/tree/master/zed_display_rviz2) +- ROS 2 plugin for ZED2 to visualize the results of the Object Detection and Body Tracking modules (bounding boxes and skeletons): [rviz-plugin-zed-od](https://github.com/stereolabs/zed-ros2-examples/tree/master/rviz-plugin-zed-od) + +### Tutorials + +A series of tutorials is provided to better understand how to use the ZED nodes in the ROS 2 environment : + +- [Video subscribing](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_video_tutorial): `zed_video_tutorial` - In this tutorial, you will learn how to write a simple node that subscribes to messages of type `sensor_msgs/Image` to retrieve the Left and Right rectified images published by the ZED node. +- [Depth subscribing](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_depth_tutorial): `zed_depth_tutorial` - In this tutorial, you will learn how to write a simple node that subscribes to messages of type `sensor_msgs/Image` to retrieve the depth images published by the ZED node and to get the measured distance at the center of the image. +- [Pose/Odometry subscribing](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_pose_tutorial): `zed_pose_tutorial` - In this tutorial, you will learn how to write a simple node that subscribes to messages of type `geometry_msgs/PoseStamped` and `nav_msgs/Odometry` to retrieve the position and the odometry of the camera while moving in the world. +- [ROS 2 Composition + BGRA2BGR conversion](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_rgb_convert): `zed_rgb_convert` - In this tutorial, you will learn how to use the concept of "ROS 2 Composition" and "Intra Process Communication" to write a ROS 2 component that gets a 4 channel BGRA image as input and re-publishes it as 3 channels BGR image. +- [ROS 2 Multi-Camera](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_multi_camera): `zed_multi_camera` - In this tutorial, you will learn how to use the provided launch file to start a multi-camera robot configuration. +- [ROS 2 Multi-Camera + Intra Process Communication](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_ipc): `zed_ipc - In this tutorial, you will learn how to use the provided launch file to start a multi-camera configuration, and load a new processing node in the same process to leverage Intra Process Communication with ROS 2composition. +- [Robot integration](https://github.com/stereolabs/zed-ros2-examples/tree/master/tutorials/zed_robot_integration): `zed_robot_integration` - In this tutorial, you will learn how to add one or more ZED cameras to a robot configuration. + +### Examples + +How to use the ZED ROS 2 nodes alongside other ROS 2 packages or advanced features. + +- [zed_aruco_localization](https://github.com/stereolabs/zed-ros2-examples/tree/master/examples/zed_aruco_localization): Use localized ArUco tag as a reference for localization. +- [zed_depth_to_laserscan](https://github.com/stereolabs/zed-ros2-examples/tree/master/examples/zed_depth_to_laserscan): Convert ZED Depth maps into virtual Laser Scans using + +## Update the local repository + +To update the repository to the latest release, use the following command that will retrieve the latest commits of `zed-ros2-wrapper` and of all the submodules: + +```bash +git checkout master # if you are not on the main branch +git pull +``` + +Clean the cache of your colcon workspace before compiling with the `colcon build` command to be sure that everything will work as expected: + +```bash +cd # replace with your workspace folder, for example ~/ros2_ws/src/ +rm -r install +rm -r build +rm -r log +colcon build --symlink-install --cmake-args=-DCMAKE_BUILD_TYPE=Release --parallel-workers $(nproc) +``` + +## Known issues + +- Nothing to report yet. + +If you find a bug or want to request a new feature, please open an issue on the [GitHub issues page](https://github.com/stereolabs/zed-ros2-wrapper/issues). diff --git a/src/lib/zed-ros2-wrapper/docker/Dockerfile.desktop-humble b/src/lib/zed-ros2-wrapper/docker/Dockerfile.desktop-humble new file mode 100644 index 0000000000..cf584a4450 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/docker/Dockerfile.desktop-humble @@ -0,0 +1,134 @@ +ARG UBUNTU_MAJOR=22 +ARG UBUNTU_MINOR=04 +ARG CUDA_MAJOR=12 +ARG CUDA_MINOR=6 +ARG CUDA_PATCH=3 +ARG ZED_SDK_MAJOR=4 +ARG ZED_SDK_MINOR=2 +ARG ZED_SDK_PATCH=5 + +ARG IMAGE_NAME=nvcr.io/nvidia/cuda:${CUDA_MAJOR}.${CUDA_MINOR}.${CUDA_PATCH}-devel-ubuntu${UBUNTU_MAJOR}.${UBUNTU_MINOR} + +FROM ${IMAGE_NAME} + +ARG UBUNTU_MAJOR=22 +ARG UBUNTU_MINOR=04 +ARG CUDA_MAJOR=12 +ARG CUDA_MINOR=6 +ARG CUDA_PATCH=3 +ARG ZED_SDK_MAJOR=4 +ARG ZED_SDK_MINOR=2 +ARG ZED_SDK_PATCH=3 +# Optional: Override ZED SDK URL +ARG CUSTOM_ZED_SDK_URL="" + +ARG ROS2_DIST=humble # ROS 2 distribution + +ARG DEBIAN_FRONTEND=noninteractive + +ENV NVIDIA_DRIVER_CAPABILITIES \ + ${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}compute,video,utility + +# Disable apt-get warnings +RUN apt-get update || true && apt-get install -y --no-install-recommends apt-utils dialog curl && \ + rm -rf /var/lib/apt/lists/* + +ENV ZED_SDK_URL=${CUSTOM_ZED_SDK_URL:-"https://download.stereolabs.com/zedsdk/${ZED_SDK_MAJOR}.${ZED_SDK_MINOR}.${ZED_SDK_PATCH}/cu${CUDA_MAJOR}/ubuntu${UBUNTU_MAJOR}"} + +# Check that this SDK exists +RUN echo "SDK link: $ZED_SDK_URL" +RUN if [ "$(curl -L -I "${ZED_SDK_URL}" -o /dev/null -s -w '%{http_code}\n' | head -n 1)" = "200" ]; then \ + echo "The URL points to something."; \ + else \ + echo "The URL does not point to a .run file or the file does not exist."; \ + exit 1; \ + fi + + +ENV TZ=Europe/Paris + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ + apt-get update && \ + apt-get install --yes lsb-release wget less udev sudo build-essential cmake python3 python3-dev python3-pip python3-wheel git jq libopencv-dev libpq-dev zstd usbutils && \ + rm -rf /var/lib/apt/lists/* + +############ Install ROS2 ############ + +# Set and Check Locale +RUN apt-get update || true && \ + apt-get install --no-install-recommends -y locales && \ + locale-gen en_US en_US.UTF-8 && \ + update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 && \ + export LANG=en_US.UTF-8 && \ + locale # verify settings && \ + rm -rf /var/lib/apt/lists/* + +# Setup Sources +RUN apt-get update || true && \ + apt-get install --no-install-recommends -y software-properties-common && \ + add-apt-repository universe && \ + apt-get install -y curl && \ + curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null && \ + rm -rf /var/lib/apt/lists/* + +# Install ROS 2 Base packages and Python dependencies +RUN apt-get update || true && \ + apt-get install --no-install-recommends -y \ + ros-${ROS2_DIST}-ros-base \ + python3-flake8-docstrings \ + python3-pip \ + python3-pytest-cov \ + ros-dev-tools && \ + pip3 install \ + argcomplete \ + numpy \ + empy \ + lark && \ + rm -rf /var/lib/apt/lists/* + +# Initialize rosdep +RUN rosdep init && rosdep update + +# Install the ZED SDK +RUN echo "CUDA Version $CUDA_VERSION" > /usr/local/cuda/version.txt + +# Setup the ZED SDK +RUN apt-get update -y || true && \ + apt-get install --no-install-recommends dialog bash-completion lsb-release wget less udev sudo build-essential cmake zstd python3 python3-pip libpng-dev libgomp1 -y && \ + python3 -m pip install --upgrade pip; python3 -m pip install numpy opencv-python-headless && \ + wget -q -O ZED_SDK_Linux_Ubuntu.run ${ZED_SDK_URL} && \ + chmod +x ZED_SDK_Linux_Ubuntu.run && \ + ./ZED_SDK_Linux_Ubuntu.run -- silent skip_tools skip_cuda && \ + ln -sf /lib/x86_64-linux-gnu/libusb-1.0.so.0 /usr/lib/x86_64-linux-gnu/libusb-1.0.so && \ + rm ZED_SDK_Linux_Ubuntu.run && \ + rm -rf /var/lib/apt/lists/* + +# Install the ZED ROS2 Wrapper +ENV ROS_DISTRO ${ROS2_DIST} + +# Copy the sources in the Docker image +WORKDIR /root/ros2_ws/src +COPY tmp_sources/ ./ + +# RUN ls -lah /root/ros2_ws/src/ +WORKDIR /root/ros2_ws/ + +RUN /bin/bash -c "source /opt/ros/$ROS_DISTRO/setup.bash && \ + apt-get update -y || true && rosdep update && \ + rosdep install --from-paths src --ignore-src -r -y && \ + colcon build --parallel-workers $(nproc) --symlink-install \ + --event-handlers console_direct+ --base-paths src \ + --cmake-args ' -DCMAKE_BUILD_TYPE=Release' \ + ' -DCMAKE_LIBRARY_PATH=/usr/local/cuda/lib64/stubs' \ + ' -DCMAKE_CXX_FLAGS="-Wl,--allow-shlib-undefined"' " && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /root/ros2_ws + +# Setup environment variables +COPY ros_entrypoint.sh /sbin/ros_entrypoint.sh +RUN sudo chmod 755 /sbin/ros_entrypoint.sh + +ENTRYPOINT ["/sbin/ros_entrypoint.sh"] +CMD ["bash"] diff --git a/src/lib/zed-ros2-wrapper/docker/Dockerfile.l4t-humble b/src/lib/zed-ros2-wrapper/docker/Dockerfile.l4t-humble new file mode 100644 index 0000000000..f8016742e7 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/docker/Dockerfile.l4t-humble @@ -0,0 +1,118 @@ +# Define the L4T_VERSION argument +ARG L4T_VERSION=l4t-r36.3.0 +ARG IMAGE_NAME=dustynv/ros:humble-ros-base-l4t-r36.3.0 + +FROM ${IMAGE_NAME} + +ARG ZED_SDK_MAJOR=4 +ARG ZED_SDK_MINOR=2 +ARG ZED_SDK_PATCH=3 +ARG L4T_MAJOR=36 +ARG L4T_MINOR=3 +# Optional: Override ZED SDK URL +ARG CUSTOM_ZED_SDK_URL="" + +# ROS 2 distribution +ARG ROS2_DIST=humble + +# ZED ROS2 Wrapper dependencies version +ARG XACRO_VERSION=2.0.8 +ARG DIAGNOSTICS_VERSION=4.0.0 +ARG AMENT_LINT_VERSION=0.12.11 +ARG ROBOT_LOCALIZATION_VERSION=3.5.3 +ARG ZED_MSGS_VERSION=5.0.0 +ARG NMEA_MSGS_VERSION=2.0.0 +ARG ANGLES_VERSION=1.15.0 +ARG GEOGRAPHIC_INFO_VERSION=1.0.6 +ARG POINTCLOUD_TRANSPORT_VERSION=1.0.18 +ARG POINTCLOUD_TRANSPORT_PLUGINS_VERSION=1.0.11 +ARG RMW_CYCLONEDDS_VERSION=1.3.4 +ARG BACKWARD_ROS_VERSION=1.0.7 +ENV PYPI_URL=https://pypi.jetson-ai-lab.io/jp6/cu126 + + +ENV DEBIAN_FRONTEND=noninteractive + +# ZED SDK link +ENV ZED_SDK_URL=${CUSTOM_ZED_SDK_URL:-"https://download.stereolabs.com/zedsdk/${ZED_SDK_MAJOR}.${ZED_SDK_MINOR}.${ZED_SDK_PATCH}/l4t${L4T_MAJOR}.${L4T_MINOR}/jetsons"} + +# Check that this SDK exists +RUN if [ "$(curl -L -I "${ZED_SDK_URL}" -o /dev/null -s -w '%{http_code}\n' | head -n 1)" = "200" ]; then \ + echo "The URL points to something."; \ + else \ + echo "The URL does not point to a .run file or the file does not exist."; \ + exit 1; \ + fi + +# Disable apt-get warnings +RUN curl -fsSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg && \ + apt-get update || true && apt-get install -y --no-install-recommends apt-utils dialog && \ + rm -rf /var/lib/apt/lists/* + +ENV TZ=Europe/Paris + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ + apt-get update && \ + apt-get install --yes lsb-release wget less udev sudo build-essential cmake python3 python3-dev python3-pip python3-wheel git jq libpq-dev zstd usbutils && \ + rm -rf /var/lib/apt/lists/* + +RUN echo "# R${L4T_MAJOR} (release), REVISION: ${L4T_MINOR}" > /etc/nv_tegra_release && \ + apt-get update -y || true && \ + apt-get install -y --no-install-recommends zstd wget less cmake curl gnupg2 \ + build-essential python3 python3-pip python3-dev python3-setuptools libusb-1.0-0-dev \ + libgeographic-dev libdraco-dev zlib1g-dev -y && \ + export PIP_INDEX_URL="${PYPI_URL}" && \ + pip install protobuf && \ + wget -q --no-check-certificate -O ZED_SDK_Linux_JP.run \ + ${ZED_SDK_URL} && \ + chmod +x ZED_SDK_Linux_JP.run ; ./ZED_SDK_Linux_JP.run silent skip_tools && \ + rm -rf /usr/local/zed/resources/* && \ + rm -rf ZED_SDK_Linux_JP.run && \ + rm -rf /var/lib/apt/lists/* + +# Install the ZED ROS2 Wrapper +ENV ROS_DISTRO=${ROS2_DIST} + +# Copy the sources in the Docker image +WORKDIR /root/ros2_ws/src +COPY tmp_sources/ ./ + +# Install missing dependencies from the sources +WORKDIR /root/ros2_ws/src +RUN wget https://github.com/ros/xacro/archive/refs/tags/${XACRO_VERSION}.tar.gz -O - | tar -xvz && mv xacro-${XACRO_VERSION} xacro && \ + wget https://github.com/ros/diagnostics/archive/refs/tags/${DIAGNOSTICS_VERSION}.tar.gz -O - | tar -xvz && mv diagnostics-${DIAGNOSTICS_VERSION} diagnostics && \ + wget https://github.com/ament/ament_lint/archive/refs/tags/${AMENT_LINT_VERSION}.tar.gz -O - | tar -xvz && mv ament_lint-${AMENT_LINT_VERSION} ament-lint && \ + wget https://github.com/cra-ros-pkg/robot_localization/archive/refs/tags/${ROBOT_LOCALIZATION_VERSION}.tar.gz -O - | tar -xvz && mv robot_localization-${ROBOT_LOCALIZATION_VERSION} robot-localization && \ + wget https://github.com/stereolabs/zed-ros2-interfaces/archive/refs/tags/${ZED_MSGS_VERSION}.tar.gz -O - | tar -xvz && mv zed-ros2-interfaces-${ZED_MSGS_VERSION} zed-ros2-interfaces && \ + wget https://github.com/ros-drivers/nmea_msgs/archive/refs/tags/${NMEA_MSGS_VERSION}.tar.gz -O - | tar -xvz && mv nmea_msgs-${NMEA_MSGS_VERSION} nmea_msgs && \ + wget https://github.com/ros/angles/archive/refs/tags/${ANGLES_VERSION}.tar.gz -O - | tar -xvz && mv angles-${ANGLES_VERSION} angles && \ + #wget https://github.com/ros-perception/point_cloud_transport/archive/refs/tags/${POINTCLOUD_TRANSPORT_VERSION}.tar.gz -O - | tar -xvz && mv point_cloud_transport-${POINTCLOUD_TRANSPORT_VERSION} point_cloud_transport && \ + #wget https://github.com/ros-perception/point_cloud_transport_plugins/archive/refs/tags/${POINTCLOUD_TRANSPORT_PLUGINS_VERSION}.tar.gz -O - | tar -xvz && mv point_cloud_transport_plugins-${POINTCLOUD_TRANSPORT_PLUGINS_VERSION} point_cloud_transport_plugins && \ + wget https://github.com/ros2/rmw_cyclonedds/archive/refs/tags/${RMW_CYCLONEDDS_VERSION}.tar.gz -O - | tar -xvz && mv rmw_cyclonedds-${RMW_CYCLONEDDS_VERSION} rmw_cyclonedds && \ + wget https://github.com/ros-geographic-info/geographic_info/archive/refs/tags/${GEOGRAPHIC_INFO_VERSION}.tar.gz -O - | tar -xvz && mv geographic_info-${GEOGRAPHIC_INFO_VERSION} geographic-info && \ + wget https://github.com/pal-robotics/backward_ros/archive/refs/tags/${BACKWARD_ROS_VERSION}.tar.gz -O - | tar -xvz && mv backward_ros-${BACKWARD_ROS_VERSION} backward_ros && \ + cp -r geographic-info/geographic_msgs/ . && \ + rm -rf geographic-info + +# Install cython +RUN python3 -m pip install --upgrade cython + +# Build the dependencies and the ZED ROS2 Wrapper +WORKDIR /root/ros2_ws +RUN /bin/bash -c "source /opt/ros/$ROS_DISTRO/install/setup.bash && \ + colcon build --parallel-workers $(nproc) --symlink-install \ + --event-handlers console_direct+ --base-paths src \ + --cmake-args ' -DCMAKE_BUILD_TYPE=Release' \ + ' -DCMAKE_LIBRARY_PATH=/usr/local/cuda/lib64/stubs' \ + ' -DCMAKE_CXX_FLAGS="-Wl,--allow-shlib-undefined"' \ + ' --no-warn-unused-cli' " + +WORKDIR /root/ros2_ws + +# Setup environment variables +COPY ros_entrypoint_jetson.sh /sbin/ros_entrypoint.sh +RUN sudo chmod 755 /sbin/ros_entrypoint.sh + +ENTRYPOINT ["/sbin/ros_entrypoint.sh"] +CMD ["bash"] + diff --git a/src/lib/zed-ros2-wrapper/docker/README.md b/src/lib/zed-ros2-wrapper/docker/README.md new file mode 100644 index 0000000000..145c915c59 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/docker/README.md @@ -0,0 +1,149 @@ +# Docker + +This folder contains a list of Dockerfile files to build Docker images ready to start the nodes of the *ZED ROS2 Wrapper*: + +* `Dockerfile.desktop-humble`: development desktop image for ROS 2 Humble, running on the specified Ubuntu and CUDA versions. The ZED Wrapper is copied from the source file of the current branch and compiled. +* `Dockerfile.l4t-humble`: Jetson image for ROS 2 Humble, running on the given L4T version (L4T35.4 by default). + +> :pushpin: **NOTE:** in the entrypoint files we set the value of the `ROS_DOMAIN_ID` environment +> variable to `0` that is the default value in ROS 2. +> +> If your setup requires a different value you can change it in the `ros_entrypoint_jetson.sh` and +> `ros_entrypoint.sh` file before building your image to set it automatically when starting your Docker image, +> or you can use the CLI command `export ROS_DOMAIN_ID=` when each interactive session is started. +> +> You can get more details concerning the `ROS_DOMAIN_ID` usage on the [official ROS 2 documentation](https://docs.ros.org/en/humble/Concepts/Intermediate/About-Domain-ID.html#the-ros-domain-id). + +## Cross compilation + +You can easily compile the image for Jetson from your usual Desktop PC. +For that you just need to run the following line before launching the build command: + +```bash +docker run --rm --privileged multiarch/qemu-user-static --reset -p yes +``` + +## Build the Docker images + +We provide a script to build your image with the right L4T / ZED SDK version. + +* Checkout the tag or commit of the ROS2 wrapper that you need. + + ```bash + git checkout + ``` + + e.g. to build the master branch: + + ```bash + git checkout master + ``` + +* Build the image for **Jetson**: + + ```bash + ./jetson_build_dockerfile_from_sdk_and_l4T_version.sh + ``` + +* Build the image for **Desktop**: + + ```bash + ./desktop_build_dockerfile_from_sdk_ubuntu_and_cuda_version.sh + ``` + +Examples: + +```bash +# Jetson with JP6.0 and ZED SDK v4.2.5 +./jetson_build_dockerfile_from_sdk_and_l4T_version.sh l4t-r36.3.0 zedsdk-4.2.5 +``` + +```bash +# Jetson with JP6.2 and ZED SDK v5.0.0 +./jetson_build_dockerfile_from_sdk_and_l4T_version.sh l4t-r36.4.0 zedsdk-5.0.0 +``` + +```bash +# Desktop on Ubuntu 22.04m CUDA 12.6.3 and ZED SDK v4.2.5 +./desktop_build_dockerfile_from_sdk_ubuntu_and_cuda_version.sh ubuntu-22.04 cuda-12.6.3 zedsdk-4.2.5 +``` + +> :warning: Some configurations will not work. For example, if a specific ZED SDK does not exist for a given Ubuntu/CUDA/L4T version, or if the given ROS 2 wrapper is not compatible with the selected Ubuntu version. + +## Run the Docker image + +### NVIDIA runtime + +NVIDIA drivers must be accessible from the Docker image to run the ZED SDK code on the GPU. You'll need : + +* The `nvidia` container runtime installed, following [this guide](https://www.stereolabs.com/docs/docker/install-guide-linux/#nvidia-docker) +* A specific docker runtime environment with `-gpus all` or `-e NVIDIA_DRIVER_CAPABILITIES=all` +* Docker privileged mode with `--privileged` + +### Network + +Setup the network configuration to enable the communication between the Docker image, other Docker images, and the host: + +* `--network=host`: Remove network isolation between the container and the Docker host +* `--ipc=host`: Use the host system's Inter-Process Communication namespace +* `--pid=host`: Use the host system's namespace for process ID + +### Display context to use CUDA based applications + +Use the same host `DISPLAY` environment variable in every Docker image to enable CUDA-based applications with `-e DISPLAY=$DISPLAY`. + +> :pushpin: **NOTE**: the shared volume `/tmp/.X11-unix/:/tmp/.X11-unix` is also required. + +### Volumes + +A few volumes should also be shared with the host. + +* `/tmp/.X11-unix/:/tmp/.X11-unix` is required to enable X11 server communication for CUDA-based applications +* `/usr/local/zed/settings:/usr/local/zed/settings` if you plan to use the robot in an Internet-negated area, and you previously downloaded the camera calibration files by following [this guide](https://support.stereolabs.com/hc/en-us/articles/21614848880791-How-can-I-use-the-ZED-with-Docker-on-a-robot-with-no-internet-connection). +* `/usr/local/zed/resources:/usr/local/zed/resources` if you plan to use the AI module of the ZED SDK (Object Detection, Skeleton Tracking, NEURAL depth) we suggest binding mounting a folder to avoid downloading and optimizing the AI models each time the Docker image is restarted. The first time you use the AI model inside the Docker image, it will be downloaded and optimized in the local bound-mounted folder, and stored there for the next runs. + * If you plan to use different SDK versions in different Docker images it's preferred to use a different + volume on the host for each of them: `//:/usr/local/zed/resources` +* `/dev:/dev` to share the video devices +* For GMSL2 cameras (ZED X, ZED X One) you'll also need + * `/tmp:/tmp` + * `/var/nvidia/nvcam/settings/:/var/nvidia/nvcam/settings/` + * `/etc/systemd/system/zed_x_daemon.service:/etc/systemd/system/zed_x_daemon.service` +* `/dev:/dev`: to share the video and other required devices + * `/dev/shm:/dev/shm`: to use ROS 2 with shared memory + +### Start the Docker container + +First of all, allow the container to access EGL display resources (required only once): + +```bash +sudo xhost +si:localuser:root +``` + +then you can start an interactive session: + +#### USB3 cameras + +```bash +docker run --runtime nvidia -it --privileged --network=host --ipc=host --pid=host \ + -e NVIDIA_DRIVER_CAPABILITIES=all -e DISPLAY=$DISPLAY \ + -v /tmp/.X11-unix/:/tmp/.X11-unix \ + -v /dev:/dev \ + -v /dev/shm:/dev/shm \ + -v /usr/local/zed/resources/:/usr/local/zed/resources/ \ + -v /usr/local/zed/settings/:/usr/local/zed/settings/ \ + +``` + +#### GMSL cameras + +```bash +docker run --runtime nvidia -it --privileged --network=host --ipc=host --pid=host \ + -e NVIDIA_DRIVER_CAPABILITIES=all -e DISPLAY=$DISPLAY \ + -v /tmp:/tmp \ + -v /dev:/dev \ + -v /var/nvidia/nvcam/settings/:/var/nvidia/nvcam/settings/ \ + -v /etc/systemd/system/zed_x_daemon.service:/etc/systemd/system/zed_x_daemon.service \ + -v /usr/local/zed/resources/:/usr/local/zed/resources/ \ + -v /usr/local/zed/settings/:/usr/local/zed/settings/ \ + +``` diff --git a/src/lib/zed-ros2-wrapper/docker/desktop_build_dockerfile_from_sdk_ubuntu_and_cuda_version.sh b/src/lib/zed-ros2-wrapper/docker/desktop_build_dockerfile_from_sdk_ubuntu_and_cuda_version.sh new file mode 100755 index 0000000000..eeca6a8f7c --- /dev/null +++ b/src/lib/zed-ros2-wrapper/docker/desktop_build_dockerfile_from_sdk_ubuntu_and_cuda_version.sh @@ -0,0 +1,93 @@ +#!/bin/bash +cd $(dirname $0) + +if [ "$#" -lt 3 ]; then + echo "Give Ubuntu version then CUDA version then ZED SDK version has parameters, like this:" + echo "./desktop_build_dockerfile_from_sdk_ubuntu_and_cuda_version.sh ubuntu-22.04 cuda-12.6.3 zedsdk-4.2.3" + exit 1 +fi + +# Ubuntu version +# Verify the format (l4t-r digits.digits.digits) +if ! [[ $1 =~ ^ubuntu-[0-9]+\.[0-9]+$ ]]; then + echo "Invalid Ubuntu version format." + exit 1 +fi + +ubuntu_version=$1 +ubuntu_version_number="${ubuntu_version#ubuntu-}" + +# Split the string and assign to variables +IFS='.' read -r ubuntu_major ubuntu_minor <<< "$ubuntu_version_number" +echo "Ubuntu $ubuntu_major.$ubuntu_minor detected." + +# CUDA version +# Verify the format (l4t-r digits.digits.digits) +if ! [[ $2 =~ ^cuda-[0-9]+\.[0-9]\.[0-9]$ ]]; then + echo "Invalid CUDA version format." + exit 1 +fi + +cuda_version=$2 +cuda_version_number="${cuda_version#cuda-}" + +# Split the string and assign to variables +IFS='.' read -r cuda_major cuda_minor cuda_patch <<< "$cuda_version_number" +echo "CUDA $cuda_major.$cuda_minor.$cuda_patch detected." + + +ZED_SDK_version=$3 + +# copy the wrapper content +rm -r ./tmp_sources +mkdir -p ./tmp_sources +cp -r ../zed* ./tmp_sources + +# Check if the third arg is a custom path +CUSTOM_ZED_SDK_URL=$3 +# Use curl to check if the URL is valid (returns HTTP 200) +if [ "$(curl -L -I "${CUSTOM_ZED_SDK_URL}" -o /dev/null -s -w '%{http_code}\n' | head -n 1)" = "200" ]; then + echo "${ZED_SDK_version} detected as a valid custom installer URL" + + echo "Building dockerfile for $1, CUDA $2 and a custom ZED SDK" + + docker build -t zed_ros2_desktop_u${ubuntu_major}.${ubuntu_minor}_sdk_custom_cuda_${cuda_major}.${cuda_minor}.${cuda_patch} \ + --build-arg CUSTOM_ZED_SDK_URL=$CUSTOM_ZED_SDK_URL \ + --build-arg UBUNTU_MAJOR=$ubuntu_major \ + --build-arg UBUNTU_MINOR=$ubuntu_minor \ + --build-arg CUDA_MAJOR=$cuda_major \ + --build-arg CUDA_MINOR=$cuda_minor \ + --build-arg CUDA_PATCH=$cuda_patch \ + -f ./Dockerfile.desktop-humble . +else + # Verify the ZED SDK format (digits.digits.digits) + if ! [[ $3 =~ ^zedsdk-[0-9]\.[0-9]\.[0-9]$ ]]; then + echo "Invalid ZED SDK version format." + exit 1 + fi + + # Remove the prefix 'zedsdk-' + zed_sdk_version_number="${ZED_SDK_version#zedsdk-}" + + # Split the string and assign to variables + IFS='.' read -r sdk_major sdk_minor sdk_patch <<< "$zed_sdk_version_number" + echo "ZED SDK $major.$minor.$patch detected." + + echo "Building dockerfile for $1, CUDA $2 and ZED SDK $3" + + docker build -t zed_ros2_desktop_u${ubuntu_major}.${ubuntu_minor}_sdk_${sdk_major}.${sdk_minor}.${sdk_patch}_cuda_${cuda_major}.${cuda_minor}.${cuda_patch} \ + --build-arg ZED_SDK_MAJOR=$sdk_major \ + --build-arg ZED_SDK_MINOR=$sdk_minor \ + --build-arg ZED_SDK_PATCH=$sdk_patch \ + --build-arg UBUNTU_MAJOR=$ubuntu_major \ + --build-arg UBUNTU_MINOR=$ubuntu_minor \ + --build-arg CUDA_MAJOR=$cuda_major \ + --build-arg CUDA_MINOR=$cuda_minor \ + --build-arg CUDA_PATCH=$cuda_patch \ + -f ./Dockerfile.desktop-humble . +fi + +########### + +# Remove the temporary folder +rm -r ./tmp_sources \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/docker/jetson_build_dockerfile_from_sdk_and_l4T_version.sh b/src/lib/zed-ros2-wrapper/docker/jetson_build_dockerfile_from_sdk_and_l4T_version.sh new file mode 100755 index 0000000000..f1560b7b64 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/docker/jetson_build_dockerfile_from_sdk_and_l4T_version.sh @@ -0,0 +1,85 @@ +#!/bin/bash +cd $(dirname $0) + +if [ "$#" -lt 2 ]; then + echo "Please enter valid L4T version and ZED SDK version has parameters. For example:" + echo "./jetson_build_dockerfile_from_sdk_and_l4T_version.sh l4t-r36.3.0 zedsdk-4.2.5" + exit 1 +fi + +# L4T version +# Verify the format (l4t-r digits.digits.digits) +if ! [[ $1 =~ ^l4t-r[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Invalid L4T version format." + exit 1 +fi + +L4T_version=$1 +# Remove the prefix 'l4t-r' +l4t_version_number="${L4T_version#l4t-r}" + + +ZED_SDK_version=$2 + + +# copy the wrapper content +rm -r ./tmp_sources +mkdir -p ./tmp_sources +cp -r ../zed* ./tmp_sources + +# Split the string and assign to variables +IFS='.' read -r l4t_major l4t_minor l4t_patch <<< "$l4t_version_number" +########### + +L4T_VERSION=${1:-l4t-r${l4t_major}.${l4t_minor}.${l4t_patch}} + +# Determine the IMAGE_NAME based on the L4T_VERSION +if [[ "$L4T_VERSION" == *"l4t-r36.4"* ]]; then + IMAGE_NAME="dustynv/ros:humble-desktop-${L4T_VERSION}" +else + IMAGE_NAME="dustynv/ros:humble-ros-base-${L4T_VERSION}" +fi + +# Check if the third arg is a custom path +CUSTOM_ZED_SDK_URL=$2 +# Use curl to check if the URL is valid (returns HTTP 200) +if [ "$(curl -L -I "${CUSTOM_ZED_SDK_URL}" -o /dev/null -s -w '%{http_code}\n' | head -n 1)" = "200" ]; then + echo "${ZED_SDK_version} detected as a valid custom installer URL" + + echo "Building dockerfile for $1 and a custom ZED SDK" + + docker build -t zed_ros2_l4t_${l4t_major}.${l4t_minor}.${l4t_patch}_sdk_custom \ + --build-arg CUSTOM_ZED_SDK_URL=$CUSTOM_ZED_SDK_URL \ + --build-arg L4T_VERSION=$1 \ + --build-arg L4T_MAJOR=$l4t_major \ + --build-arg L4T_MINOR=$l4t_minor \ + --build-arg IMAGE_NAME=$IMAGE_NAME \ + -f ./Dockerfile.l4t-humble . +else + # Verify the ZED SDK format (digits.digits.digits) + if ! [[ $2 =~ ^zedsdk-[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Invalid ZED SDK version format." + exit 1 + fi + + # Remove the prefix 'zedsdk-' + zed_sdk_version_number="${ZED_SDK_version#zedsdk-}" + + # Split the string and assign to variables + IFS='.' read -r sdk_major sdk_minor sdk_patch <<< "$zed_sdk_version_number" + + echo "Building dockerfile for $1 and ZED SDK $2" + + docker build -t zed_ros2_l4t_${l4t_major}.${l4t_minor}.${l4t_patch}_sdk_${sdk_major}.${sdk_minor}.${sdk_patch} \ + --build-arg ZED_SDK_MAJOR=$sdk_major \ + --build-arg ZED_SDK_MINOR=$sdk_minor \ + --build-arg ZED_SDK_PATCH=$sdk_patch \ + --build-arg L4T_VERSION=$1 \ + --build-arg L4T_MAJOR=$l4t_major \ + --build-arg L4T_MINOR=$l4t_minor \ + --build-arg IMAGE_NAME=$IMAGE_NAME \ + -f ./Dockerfile.l4t-humble . +fi + +# Remove the temporary folder +rm -r ./tmp_sources \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/docker/ros_entrypoint.sh b/src/lib/zed-ros2-wrapper/docker/ros_entrypoint.sh new file mode 100644 index 0000000000..09c0b2b511 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/docker/ros_entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +# setup ros2 environment +source "/opt/ros/$ROS_DISTRO/setup.bash" -- +source "/root/ros2_ws/install/local_setup.bash" -- + +export ROS_DOMAIN_ID=0 + +# Welcome information +echo "ZED ROS2 Docker Image" +echo "---------------------" +echo 'ROS distro: ' $ROS_DISTRO +echo 'DDS middleware: ' $RMW_IMPLEMENTATION +echo 'ROS 2 Workspaces:' $COLCON_PREFIX_PATH +echo 'ROS 2 Domain ID:' $ROS_DOMAIN_ID +echo ' * Note: Host and Docker image Domain ID must match to allow communication' +echo 'Local IPs:' $(hostname -I) +echo "---" +echo 'Available ZED packages:' +ros2 pkg list | grep zed +echo "---------------------" +echo 'To start a ZED camera node:' +echo ' ros2 launch zed_wrapper zed_camera.launch.py camera_model:=' +echo "---------------------" +exec "$@" diff --git a/src/lib/zed-ros2-wrapper/docker/ros_entrypoint_jetson.sh b/src/lib/zed-ros2-wrapper/docker/ros_entrypoint_jetson.sh new file mode 100644 index 0000000000..2899d1e9d8 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/docker/ros_entrypoint_jetson.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +# setup ros2 environment +source "/opt/ros/$ROS_DISTRO/install/setup.bash" +source "/root/ros2_ws/install/local_setup.bash" + +export ROS_DOMAIN_ID=0 + +# Welcome information +echo "ZED ROS2 Docker Image" +echo "---------------------" +echo 'ROS distro: ' $ROS_DISTRO +echo 'DDS middleware: ' $RMW_IMPLEMENTATION +echo 'ROS 2 Workspaces:' $COLCON_PREFIX_PATH +echo 'ROS 2 Domain ID:' $ROS_DOMAIN_ID +echo ' * Note: Host and Docker image Domain ID must match to allow communication' +echo 'Local IPs:' $(hostname -I) +echo "---" +echo 'Available ZED packages:' +ros2 pkg list | grep zed +echo "---------------------" +echo 'To start a ZED camera node:' +echo ' ros2 launch zed_wrapper zed_camera.launch.py camera_model:=' +echo "---------------------" +exec "$@" diff --git a/src/lib/zed-ros2-wrapper/images/.gitkeep b/src/lib/zed-ros2-wrapper/images/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/lib/zed-ros2-wrapper/images/Picto+STEREOLABS_Black.jpg b/src/lib/zed-ros2-wrapper/images/Picto+STEREOLABS_Black.jpg new file mode 100644 index 0000000000000000000000000000000000000000..060e243577740d8975c813f747e4c894d477518a GIT binary patch literal 15698 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 literal 0 HcmV?d00001 diff --git a/src/lib/zed-ros2-wrapper/images/PointCloud_Depth_ROS.jpg b/src/lib/zed-ros2-wrapper/images/PointCloud_Depth_ROS.jpg new file mode 100644 index 0000000000000000000000000000000000000000..467a3dedd3530221f1b152cef3a1fe6590d79f55 GIT binary patch literal 154842 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 z�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 literal 0 HcmV?d00001 diff --git a/src/lib/zed-ros2-wrapper/images/depth.jpg b/src/lib/zed-ros2-wrapper/images/depth.jpg new file mode 100644 index 0000000000000000000000000000000000000000..542ed9d03126645a78e13ca194c5edb616eb5eff GIT binary patch literal 55257 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�=mqP#2J$>F6YB74&wOL`wI7e2I)@YU%_w!* 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ⅆS?$=ycnf+MhcQ$hQ7nQ@btHF@gwtIs()fk zG=V3@Hc^EUQ*m0EAGgQ)*95|t$O5Wx4F~PTMh!|U1#pqsF0cm(d~br`QK;)j!<{$G zWe{+vZ<5y>H#Wz6L^IO2GGz|q`w8441p3h(*G$kT1G8S zLYGe#Q71s)CwKyA8$*kKS1TXR0{|KnCE(ZF@Q<*u?mUnTqLL{XNE&0uL%5Ok_rcN} zD^3`e=<%ue3IKNhU25N8P(*buO%3&ugV!|{Ux|u!rhw@T>`9VCf#hL_q$F%!lJm4$ z7?1IDT0WKnXfgxl0Uf9I;<Cmb3jU*c-3El51D12~14CA!hPqYOA zpi{S1ymz>hoBdcO){hIuvoHr)*gPIOijpZ6m2@@&eQ_uOQ*dou5%WnSjte3b>t(FeM`35=p=OOB#a9or85zRJew(Mja7w<-msbSvN;o zBy=3JUf!a{XCm%q=qK z$5E102Sw(I+Z$UT>JxD9w9+ga-%5~%6QFl7bxuXSa=Xa8Xn3bI&_dnZwZ(KfaucrF zvpXTj@eIr)3^cA5`O2}id3woxRa$vK5W`7KvNVP&wBh0*!{OVd_QhueCsFxf@IrS` z#T2f#6;9FtPshO3iSR#aOLw?9JF$6U%M5piffRs3ZKFL8LX3;qn<@F1B9oy4YwFK*2yEJRR&&GXp7h8Q1x3m_wm@K}$ z$ZnIr) zBgwZrShYKav~NA$?poRIe!Ja6kR{mOCh7ww61@!s6Olbeo|UbECtGUIw1&>5vfcEDW4qax@lXvj(y$2G)5fK{TbHN&ovd=iJ_3r!o!9_yC6yXr=Us|JisfmoXeWcFxcqN9Iag4Xu~5ddC!V$6TUezEcqT!FEVIoof+o& zJ6R7l-Ef7YWv265cj{c=l;j^hOgj5OT7OSoh-7FoPQz*qQhVCHz=9d70tAkT-AZ>8 zK5syX|M%GXtkC9Hw>EgO)MPulnvLE($I=OaWh*q!)NIqvpYz#PlP{z?q+iBWao6ke zSj}z`XzAE(k@wont^F5&{Sr`Y0Wi8$ zwxIBIj#m3z>lO8AN)J-}u*wx;oA8~ngE@aCui>q}qFH}tTG&5lTD1p#nu6%LbT}YQ zsqwNqzWg#22z4^#jaaV;%{Y*?L;;2AvJA8onOfa0TIBBFEY|)|f>cgRd{~{!YrpIT z7-m_s#nygGkp403>Nybrk@d%mvB2Wo`-U`|wF4_}l8Q{9ONDmxVHkzzL3^CyZmLg+ zq5^Z=W$P%;EAUS?%rfp*?jiI}-+8kXOw$FctX z*H}7_y+C48=jdhVJZUSb6lW2YN z(@d;+X!VIpP5p$oB#dPvStrPT@?dLt;fj;D@*3BriZ7uB;09sQ9X@@+k%?J9a9JK- z4vGA2>(o&f^diH>pR%#uCJrLrJ^4q@spk)>Apd2Yu9Z zH;>PYxps5$g+*`XF+SvTI@%ABu&ODguSu^-6Fo(@P~1%V<4gL-m&K$myptG~a}e;Q zAvXu9h{RJ6N^07UWt$aFh?6^CSOeskx}PQ{b&x71b4&9IbkDQ zVVjB`@u$2T^NA_JT_9b<;HKl7q}FrfJ1&z4r~_CTrt+@|jIFI9?NUB1U;|J+`*zH} zYY%i1ecnr|BnJuBk%Zy~VPY3(*#MzbIEveA96$7sz=kXG2Qzc~`+aUL^r4_l#b%2^ zO_v{KO2UCFXJed@f>noHuLBcX*!p-%f8u8T)LS z@p|n=$8z5JjcNgRQ|c#O1JF$`M}*zUMh{#@BnU!vSUWy= z>}%H6g>sC%M*E@vXSU9NgvT9~9)-D9!>Vydv+FAtq6{982t~)*E>j2}1^b*YB>fyY z`fCzKu>TZD0(YK$JNHrWZ^&_X`R}Fh?SJy}^|$N4SJ;?kRaK)6t~`Hr(EIMfnbD1p zR{WowqPssDynoGx@Yg0r?=E+Y{`z*D52*w1@mB}De=k(>H)g!=t&NZVUcSx$#VfkE z@yVON_L~2Db@blvl~Mlh^|ZSCFs+c~G-MDBokYV{&;&YZLK8HRRT?OhE@qxC5tI&b zjbtj)(BlAp?piI-GO!JCN z%g#*eiA>woOp;8NgL#%yP}bI@EZ2%G_s%Tnve|1ji!77vYo6^NlpUCq9aNFMqcb~n zA{%1UQe<+%&2u7ya`q46=kQc!_}dOLP;^s#rz9NEw556^xS~(3%|B02Ej8 z=wPvO*dh)~z-OE1O1?*CGX!o>aDRy^1pyc_UtAPz+Z$JLG83&uhVjYxMJSW?71E(W z$`JG{AAz^b3wz1Kt1XmDFPEmkaTw6-aFn>w9=QQE47XTdFB>;diuP+mg7{Fu`K;%Mw1TLi&X!KtO8~ z039~IWlU$4q0)UK)$I@%3i>m4;A_QTp*J15>Ml07S60$^UlqjQRk9&hTh71 zbcKUDnQd3a6Rcko?5E&L#u}cqGroS-ms`f`5P*m>Bvc0vMiY7_Mv+=tcGfE*;mUGzlV1yTZZB|}jb2|8JL#ZwnO zeG^z`2Kof3H0|iIQ**e+$GDmmDjY&sr_`eVoJ8}GaEibhQ{=JR_3FGU50iECxws2F z^e!Son+9LYLLQ-FDmG!x5LB`d;$8I9f|o0VH`{#wiMJ3$#}W~57Xds64PB#r;Nrja z9=j+DROg+KUzOMeU=H)pyBP@WEy!?=@8DsKCmWf`#QFdhpQ|spJ}lAyd_i#O!UpLk zm4iTVp(q-z%Z9;0j3n!}@HRR#5BQL9I+(UKfg7-sy4#h8-m?djKZZ;wE)n9--!NJC zE2?aR$|?X+IH?R@&**-%j{n8Em4S6)S^x+w;zhIM%cS^PGdPSQy!-+zD1#Gd$YN)N zE9CWsR$nx96ww-+cl+8<_m(f6Ar>`9$$%w6?Wc^uw=X60Aw9PDHK889ce}AV4Pj!2 zEBzEp@B@dk*@wrk+s66_yz#1y9 z005n*Vqqj;m|ukr%u^{*^R{Lp{?&PR<|bIj$89mJ(|=-(vwCDbSM9VFw5=9dA`~AF z$NzLKUb7d#FpK&UkZkHBWJ9TXN6?LyTtgK}|0V`>jUXKfSECN2;)m5K@cK~j^@022 z3M21y;p$M-jY+C<(NM8U z@HPZ}>`6{Q#ODM1m5TF8h9Lg{U8!fVW>6bO5jmyx5W6hE^(C1(5U*;Y@w z(k>dC>XiJKh{}?|Q!L*K>;Ei*TD4kvm`PJ@F#y z{EL`7FAltU5&P=}RdGDQX8iEZ@gpb3lg^JP-x*JNGoJcuoTfODVKb4nb0X)&#BR;= z^g9y;Zzc+VO)wN+x=kgQeAR~R-v_dh@XV|sn_=%|jj7MWF-URv+Iz3+(jwRHiBOLx+q zX&?zCE|&(;EB#+6(2PGl1RM|`X$J`=7jup^_vr7Ffrz+Y?;Z$C>Br8naimSBDh((} zfuTZyjSr9TYZS3+THZ<-iEFwU?Tw=jpN_3zU;S?IuCYXr&G;{$8r_8I0M9OCZj}zn zzlm<0&gl~?{KoCR?XLcIHS#v_M3**fhm@Q0u zG741e0~M)TPr~FStYzzWJ8onr`T`I2$dB!2S$$qsvm0uH$Z8)@&HmFy-y=gl5>&IA z6$)0jd+Aj1Dof^X)9br-luT$OOjYslYW-{JPkuN@!0!PJNF7G zOH!Z@bQHZ>67D{*DHmYO^D;*xG-Rk4VW6AeI%=J?&^8*O1~Agi9bQC~kaK=7o+@$o z?}@4#)VO@$bZMZWOnKJ9nb&Qx2k4g$!YT$CjRj3XF(wW0e2CAjfcV2*COKH}xp||V z3}LVrkQG`jvVj!KMXY|g+jI8-Ox2WBC>489&VLq}BaiNr1{%S5K`Hma^piSv)2T)z zc`*+j-fngh;cdOb>Kj#uE_^eAL=l-WTawDF?=A501B=7kp%s((`L_f2r7V4>kh$gG zPEXvdT^oOQe~DLXI3R5@L9jEBV4!671QAFG{YCLPR-@!LnTt_xkS@3EB^1Epxh>dfWLBH7uw}4sAXK%)?%=~b$`Fc7K)*X z`~(nzsag|FSI2%XJT|)s&eVKC4~)V;k3B03>XmlBxk+cbt3$i#SUjr_%O>G>jn)5N zOAMHD7M#rqn7KP>R^7e0`sw;HP5?`B@9T?0<)poSSG%$wIz>1PuJlUN@^8&3e8yutu#)4(}w6JU?nqhXIUEf1BE0(6%d_)+lnGq)4wr_uThdg5Do z$+;g>BvavhWtu8Sj*sMKnjrO}Xw{AaXc`uNNg!yzZ|s-9>wO)K{o0xFVRF})k{42% z!?G+?-%?!}M#6P*`_D1S8&gGcci@1tx~N|#^i<|nN9ejsR)+`P)7~*(L~G~N!Fkyx zQSm1&cs-IVYPN&aQ`;bcXQGSs>^fY3xI}|?iIlfNfU~89E&4QVoXx}sNg8L+AW22oiz_SB?^+*g$O><@ zdU%`R$j=9U03v8Qpg}Oqa}okjPup`$d-nCl6)skT_fLAc9!4ooGcgoOhH49tb2J<# z80zC;vtU?sY~p?0GFy|O>Z+AWa3Ms{{@T3S^B_eAs4jVrx%xJs*KwzpaQMkaa;}c# z)likMD{F%8-az?eEpEmz-omvILk%dK=;L`%U>l}nzK7$i&tv8U@y8R0Afuvv?4nZ$xi zO)%vH_keao)mj=VE8Q~(=|VlhT~qC~N)QRXAkx1U7*+*d4#t^cdoO23*8XYmTm0C@ zJwVBne`}s2@$3;7trnS?a)0pc$XG|T2-5`C`869?GnG!?YtkVJ?Ahu;Lnx2{vmoCr z#mDcY_V-`VJmz7s)t=!NgcOHi?~9We8A|KsD4A2uCv!a_^F2Itb!%dsWe%S-Yn*x* zOLjbc2Hv6?@^eW1Grr_TWqrO@l#oq)1_w^rt_zu7MMY1BrC}vZm5%UL;-u(0LcV)U zUjH0HMmLd0A{pl1kt0da$-tjFz$kK)gIjxz`0%I9)t4MbVSAnCRgg+vds^Y;YOZQO z>2X}{8F!{1Z|fQ3X68Ux-nnxtZV&O7L5wm{)XB{K&oOJuYgyL^c40tWKR{olc^1l6Q zd}R6N?O$K1MYktEd98H4{`D>Cf2$6#u}fsWt}SZUp`6w38JFG0Bc;E8GucKN}s? zlWgdj`{p?e#{;71IgVr~tNz*GrvHU6LbZ@5;u+_VbKMlLOegVW=_V={4V#vyI9YBvtLIBEh7lxA3>M2Q;^VTA1S)VJz|VsC zdD8AA+`m9}fYS|Mt38{P?nb5UgqiF;rmR6n`7^XHmgH*F!EaHg58c8i{#1QAVFImW z4)OqHaF=cZ8ek(C5dgr2UrEBRvR%S|mM@=yHYqYOIGO2|;LLPl_-V#H*V75XI&MGl z2TSl9L_vUt%sGoGg?v`Q=PMxo92f1$i~K1g3?p0oFfJ|PTcpuomQIe2uxSZAO!bqS z%(UofRDALG)w7A89hU(k5gu@y2V9yDs}of+bwb7vJSUibql~VK`Fuceum` zr=rQQd_&VQgkx&$Zb|Y34~gr={M`Rl=8U{tkz%p|5n57#Xn+E!kdXdHF55&=kf&IM z3|;#`TbZ(5hZtsZw99S5NbxHFaLbXB^4)C7FBK$=;b|Kg;DXzkOBHno!^NOJ?=84H z;l5Z%i*XzWj-XY1ZLOeaUl7zuJGST=$0wO3s(?$7W%;KmLoV#R8(1xy_&5?Di*(s4 zVWKehN3wCq5)&xg0`;3m`p~FhNW)Gvh16)BySMk|8?^U)p zCku&ZTSb{8ik1YH*di;mpxr<5xa8VAxwNVecITfXEEve{G1r5&`|pIwlit@mMAuz- zSp9y; z0D((4von~Euhn0cWnV&f;0)o6y*5S?H+FH6sk1p!I8-tZTLB7GfVW%Z1!%NR(Ynqy zzjG!OKmpLw^$nDy!U0g&Ke}xHNzIY`TF-ZI_><^nDFGYJXmSt=|3qwlEK5o>d&kKj z|NDfOj5rz3Wc7})bnCL9W1jaBHXbq+hH9*b>OzO=3u2v;hnl;Gu1pSH z+ZbXgJZiOm)E@fiX3C?^sz+VjkGdxx-Q9S^R(RZN{kT8$@q?7dgH?}*x*tEDd_1!8 zn4>WK)Or|}D=XkIJW)0Ls(W~Ha`>&T_^IV#%>dA%a#(=^&aVy6ri}anv@=JLQ|Ecs zqbQY=a9G8d!U(2%^glA%|Ew^eF7tn9g`raR-(O*jHD0fKSfbq482T`w?%%C2V2##S zj9x#L;)lg$=OC_1CVGPtK=a=0|3d%$R>v)S0SQ-+P3=7H(UK1ls=XF zuM}mYT@x4R8c|p=bq5Uphp1NLjs5m%zp)vR$+uGPq~;%@K}TFBezV}fq)(e|A}mk= z$GiU1F5_k7siAVt#icJV&ac1k=x2Xzxz~4+uk8JHhPP-XTRIkc6jhk^Y2x9&)R6}i zKmM4?c$~MwZ(y!noJpITX&A9Jn8*o<_yFBOWr7Y_Z;z2tY{J%!$j0iNIrWA|nf&z@TaOeX7OU;e~j zQ0Xn5LP}X10@^DO2flfp72$0q;>u^apx_0BZMGU`gYg*x8Am@~XQKthk`cigU_)Z- zN>k|uU5<@ZY=_abSIqYvG=z>a9?0uS05rlzV_(rVzEjskc5nUVZ(X?i7GW(`KJ8Q8 z1{qzW7cR zZk1b#x6=?}z~v~NDobO&mtkX)wj4{33tJYG1#pzAp2P- zMFyKhgrT+t&(xs>;Dh`mHCwX_!TKY23lFYNz5nH*(BeMwJggMBdGNgLuw*6;m1F|T z4hf*8JHu2c@9~9&HPP}?6g7xwuwQgN*8cETleiohSMV6!^zC9ey24Dvr`uv$S6kQdi8rcL(o52*F`k-DF1~!s46#nQ$TF3gp~oG`}L3Z{l>#^@B$$Sitm{tZ5mK zkJN|XDiwhT0vV)PQo=*~`P6Sve|`{W9kp)otr{3Lk?`qU6V( z<(xByfrPLfP4Jh(fk8APH&c-u$vwLApv&r*Qf!TBao9B%f$*Amx>IJiMYMmn{&aV-Uz`F(`m0GBu%P6S`4HndT*thNVtN)v=hZHGM z(Tc8L=DZ_IVQMJ54jF_YE3@o!Mmi)t3Tt%9S}~k@_b!5<9+XbUm9&c(tn|Xno!SQb z!^Hh2P&?uwqJhVIIev_&U{A}bqmTd5dJt)4{1lbT_x#MRRKs-|TbMoShCN zF$t<*4+goAkXb-M!a8qZ58J{;E4YBbMCSKpoBiFgzh<cJ4FsHXtfC(%hf$}X%^TMinmo%qMpTOI3 zlds;14mSwH`1PMji01dYU z;-CAfdCt(8(kC}~Hz%{bT?=gD6ENpzW8I0JR%HMwqiJ3SU-0qH7l_u%C^eBb@ooEmAiD z?lbTT{rKcyrxVc{4nGTH=q3B@<0UkAWS<4q8D3Ul_6q5^_Tb8!(E>6Y2Z>-YWhr0@ zT2Fug#O(Xcw!iQx-7P5Ht<)`Ph5poB>9qtKGZFOk#1BKFuKz&~1(JxIo@9p90EIAk;=nRHjz*V+rSI9m&f}C|n z_2%uTc%q-+5#ivPj|jikf225(-H{WfEejRaC-Zh(GYOcJ7Bg`LG^mHnj)Gc&ponI; z^j^4bGhBD5Mi)Y1P%+R62HaBi3vGv(DfosMFpzuNeFdLr8ZPbw6J^A^CfB(S6}#+! zN0DnAqj!k~s$IPlC_S$bM*w39AWW7D+n)6?5Dd!|-NT~w!2*S3>u2k?%e2P|y$BC` zB@aqA9Ny7zB)K8!TtjkKL&~d$RLg)S0=S*mVBA8>(h&=#Hs*IV7EoU`7Opii zn@;ce|0zs9DHqq|o{lucyp?E%!sOrem(T7v1f#;Fxy=KVD>XatkuR&6UA35&+JD~+ zxC=D{uUI)bL4+E1L_Y?5I3DUL%ikh;|5{n{#8BqF4dL& zZFT0Wd~d9L=_+|>EEi7<*!#Q6{l-74=jY}8m2an&BE<+GZ4PKdps}40VU*SZ4PO9* z=_#Ql-T~#v9oPT5M{_w6uyTDg-4V8+HKN86QE_ERp+J*h$YFXyU$Cb8)}f2m45|eE znY#O1cB9{AsCvHiuqV#~yWz6_7b&rAt77HO+bit1ch>LdaM1amb+46f-aXQ7@mCLj zA#$~$P|+%J5j%cXkTk@Zg-xLNtNUUU?j4%CzWrWmp>q8bpBg0TTld{x>#K`Lrw8uY z-MfD50MFZcYmUJ0yR6-uEs~ ztA0lA@Y7#^1X%r$p%@+n4LYdPi;z%@sQ%s%dRQV3&Q84NR5H&AzWh@&oBgDmgpHx5 z_alH#Ha>lW%-0E*P>=b8mHYTMZYxs))Wg;7sDP%1(;W(YL9L7iB!7ve!9*k@|)cwJ6itumkgw;)|*y^S&+QVZx9>(IqoH?YD z7=ifMajVxWjp+8+kRKC~_&b}^?g+@x(yVXxjf$WZ$c_ zW7~^rY$o=_6@9NY>wo{sOoBOx5bX4<)P1~7o@BRz1WybcEYP~S^ke)lg@f;(qv>cE zdk6E~FUq7Mnw7KIJ|OY=INNUTz)i%SZPewHOk_wzroavk+H#PF>FO|gW_S%mH6rY$ z?JKrp*&>P+Qa`#e?IWJNY~rN57M$2ePU+1t-RR$ZfDJnpef{7{5)9z05@;54j*7GF zazGUT1g;n;*~t4HVQrE7d7qbWSa&v%=fZI06`9=#mRI*@XGm6Loa}=vR{nqn@kNeZ zEwxmz#nolaGg2^wm7lmAb^eeO1~G#pnW8OR(+eCGXGAfk=)6<0RfysbggSMo$-TcF zA*Pf`Q8bIb^NjrA0RJaO6(G`pMrZx~vaX>+;S67~NL^@41;Y|IdnYWEGfU+puRN7J zzM&>pL2wO%6Fmy+xD|ue_0o|UkM>$FZn1B{*qfM$(VM2ujZgO)cRUmK2{^Q1Xa(Qea{Sy)mtt#kxw=ILqk~e zj-}?H;pV`Oq3732mPX zBLQt{LA3%{qaEY?63H8-Q_O?IF@HkA4z}<$YHr9KCsKcBzvs1tGZ0qJa^)81)V0I^ z=b|jD1<+CGj~-bxTg~{y_u3F z0}lJ^Hm@;0x~RS&Zb7ooy(p;gXrGBXNm|={vEm>AU90V&LcQU1fyQTrsT~p4 zZ6FMeq+w?zbd-1#P$%8~yx|n$IB^ZMo8@R8cwKqJe=S#JdARU#kD42t!k*3PDazV? zL`#{^K-rB|Dr5+etxkq+?s+{A(D86{^}w~ZH|fzAc1-Ju{bKmb#eoK+@!Gzep^z zGx3>DMAM;(Pv<|1=B%&f2+Xts@}gaG!UQoJ1-L-4-!<_vAXOTmpfW-kooQj5WpfQux)7v?d4PDSW^ zJSA17p(?OTq607M0t*e76riHKUBsgwp$++EH^Zsvl~mY*H;gQ*uN-yjHXaRE6{4s* zGEu|l9bFk{=m^vvBa4Z|uQTvnx{(|VMXxI2(NF{rVORRO3s7GO8HoRy+9OQF2tj%w zVrn7coVvxigY!venj$6#z_VWXUqtmz&U?%5dbj`yi26IV;D7PU#$U1Q@)XbNPDy1& zq;;W{Coy}=D^7CrbsnJDSWrfbp%z7 zRR;aGaM16}+T@kHR6d1+haeEP$B#hHDo)AoI#xCa#!iLYz+CJ-2-(6Mu|h6VApwLv zjtZ`<^oX@C@Qgf-&2_;{l3;A~bsg}dpa%YmYQwr)itP;v|NSZ|`&tyVolX;AL$Z&L z-*_rk)UIFD>0Q))v4~Yz^s2e2H|+o<>g9P~q$hjxT_8WV*RA2gTcgdl#z$^_+PcLS zE1o)~Up(VoJa@5pp|E(Vxp;Y``0G~js#wXoe#v+5lAjk#HVaFBHJ5CUl-_b(Z6A@gp^(4mUof~WFixQpT>kE0U|Kg2!Yw#;3tlK{MQX@V_46_ zrJc4WU>CW#@f*E~pTgQ&JwK;NMlHw&y;|vUy1cUejSJYtawTI|n2CMHf0A{%4yA3s ze@pxG<3f(Xb`sTJNIYI;2Etwy9-!$^F7z4y*gls4y8y`(l(wrLGP$!J6^1Ems#I^3-=WNO`a-quc1H^<~ zzXR-)a@_o&I~b?{+I916{ee?J%97nH6ZpzcXD!6Nwk{qV*2M-eT0d|nhjD@vy;$Aw zLG^Re#^QAaLvNjn=CBJ2;Y=saqKEm)TJWV8fLh?HFbZfZoc@z@X7lRj-K^t zcJ{gh^e2c4Ve^^I3rhV|$piX^Og>n{qkzKP?wFM)n{)RcI@{LU&lz!=pi+z+Tbd$) zd0JX4?ib>U5Ni}gMxX*{LsHp=x>D(6VesifCQQkYKzX&>0@fvkrctu)|6VAUugE*O{OyD9 zh0NWi{>`ME_UManYeCl|MceoN@~MeDZe(zBn|50P_VDfFC#qx#9kDk&5o!4BrODyn2}Chwn_D~kIKKS_N#U9bDscIr>dy>b0^d@CCx z$UD0}p-G_>p9JXc8ot$GSc`5l zGw!v~hexROu;7omwu=&e$X$P~W0q-T$|s`@5fNdAC2!{dfY?Lz=P&@FU_M zYgEJAbc^>-EctA-sQY%BH)KrwjkIR-K8)_!|7jgUS}!<0jQRNb|2Osu%&tvRc9`5U zNii9zTCFB4it%3B>^RdxqS-i1@!#C+RB?ik*3b>>)6FhY_P+|CvCVEh2xA(wX(rz!l=ypuBa+Lgsg>eS$x2(rI_p=k zq5p*$lAk&7E!s0eK{S$*wnoDU80zt*AD5Wk4YNarVun zgBMtD3G~QlttFW$A{jGEqQEQ@6ORSW=}AInh1b?|2jBPPF`Oc7+NI>iiqR9N?%cl2 zg1oo@43@H{9@%Lj#hCAzO{K$OnSR3c&8ctH2BX-FUu&-h^&6F)AMxkHfirX_>hz=T zeLO^5U;(7XU?xOtcS!H}$4!?5zt6)J1M>P}R<>X~KriEaBn7D;-1f%`0_PKG6plpw zYA=ZO%Up}jT@Pe$&dDpRH(VGpUDu#umM38f@`ra^NjnNvljwL%v`{<#K~L=0jrjW1 zNS(51hzN9r2&e!UJ0fW8LWO!3p=i`*6p7#mKzqz@c|_OwsNTvjQIQa?VZLACGMlS- zs3$@7!;INzD7xHP=MMrY7>598n1ZvqCS9ua?V!`f(u*oh9@7} z-#q;S-dr~F_-XKj*M*?#iV*y{@j4=q2=*tDTmfyXN=%{W%=e4>3RvmAJctY55fHM6s+jb zqVG&HZqHU;!77ddot4)5t~8}3ar6KcIv}wMv7|J&ykN@xIXm=tpgDc3Tf|BP5c%kK zRvu){daO_LO4;a~b(h{=Y?4*L@|E7~;ODJbp7fhzK#{rg*1dVzccHx$=my1k(N(|=?SK%4Ded{yfWR{EC#Wcg#d?8K?1k7O|V{ z^~|-uBn_jM21j-EEVH9JorD7FXXvqR(~FT*7|#6b$b8##j|_4 zr8uK?&o2B`!VPF8`H}U1uX=ul?$XFC)8*R1cl)=;%io&XEIj!XwtnJoH_xX?@uQoI zjn0M~I-JZM!UHCl{vh_ad0kHjd=tk{#)!1oYoL-CDFSNu z$2A3A$NibuVaw>_RQ<12N5YH{D?dK&d>#E_y0*M@+LSYXx4UECUD>PR&cJHA$^7{7 zCxr%&Fh4)Ve&hV6o7!t`3SIs)({WeaSMPB?9!fJQ6x)#%;s=BEh4LqHr)ruX@NK>4 z8-0z7KS$lzoW@s%y0npjKp5#hOnLi24i)q{BrE+mwC4BMYuQF`#oss8&aiKDu8=W_ z`2bUr4ko`qYpLDNmE;YSy%ce~&pI?howht1jnkQVD zyx-*Ju`a*Swo9$PCBLk9=GY&EPA>+#GWM0NBkK^|5 z611+0xI{EP78%grU!TfEGKhR|Hp+BPLw1)a14Pjn@yn@?q)zahlk6?!YvhL}XsZI{ z1xRj=7ibe9zV3`cPEDBzx%ge^kJv6jw5JX@v1O(88t6u9$)|$W8j;rn~_hlsFBdYxPI<(D7)e{f23vRH$(9_LDIkvAJ;?C~bvt^?nP=}X5`T;N^*(^W| zsPAMONKF5p#nG}?&i9Zto-?6l92eb^q4|nb`wv z$yGeEmA))@VRinvrV2a6UGvxV>;@;91H{}twD-t&!uE-svU?WqmOib)I5fFG^5mm)Ow=sbc+$Go{OO-yY<_W1#% z>YJljPR{#O@wbfl@f6E)fC5t`0YV=TpC^n`u}9kQk>3$%WSgmFTRwDRxzVh-_tx(z zYEf&zaRBd_o-u&r^S3L)Y!(56|KYL448}qnK092d5#p zAjVkiSeDG@@P6q4CyIY>o!OGa#h1?UQ4NNcEA1y@9v-Aq^Z+)h{>uTwQG!%_6)^@4 zA^TqC8ejg9D5DVeql4=O{et{+=es+pSm}N=jB?BY)_>d-^n;n4Zi54QfD-GcY8}S{ zk5KtNV0V;$Vc&M#nG!m8nJ0zU56+)Ki~p`%mm<(A%N0cH0KCZMPq{zMV3bWb=9x10 zJD&!aN5{hX{a&`zS9Ad;wg|!WS`1>CF+U_nSREp+OlFui9;HUhA(eLMctK!4bWUT; zpcwa4jB7)E0bQUUvpfIt5Au0GzbKApEX*rj&Ru33@{|Gq!3F*?RnL!s-o-*exLsQY zG^K*guHtLnDKK=SAr{laA!_g`@^3$U@d3e$WB^aW*wdAK!=2p$RFDe{?t+=G#lvc4 zp4&u;EnMc<#0OVO;U~o})!~&Ox^F+y1+>0(4edz;PJt=`@Tl$8I4^plfhcg)9}j2o zm7fdL*M#G1#adxbY(eNo4h}H6M<<=P&E!N?QVljid5*v(V_Is@n(8-*FhooVbAf-! zgN!@EcnXXI%667tUW!USHw->MfaxL2vgScgWs(9h#n}ZAsfE9s0(#2;wc7Bb^F$Wx zYz8fPsuC}MfNwV$Uh0S7Q%<{z=d8xDpZ$T!dqQoF&dGn5n7RZ-IbT0QK*o59K*pF2GY3-)MzN$*JT_nh?~< z*w?xlD}X(Uo;3u-3lwZMns2mDs=rMHAOmoURADFd|?n5=S92x?+BJlw8Sdh(Up z-ytR10DzLqRTxF>Wj(xXs}QPT$^vhoG!C)a;aDbc$S*yd$|rZ*7exTbp@D#peH|r9(4y{_kq=D zr%=D}xQ7kYUreiwa4^Rjd|^hokpkYjQw+~7t{fI{)c^mMDE|sFUXdi^KPAflVvu=N z5|Ask*PvX>=bs?sb1KWD%+?)@^t&bT3i68<>-&_NtN!g5RTby8S}FyU!T5KjhB4p) zuK!fV+y(>zXZV%>W{p$YkqRO!hPg8UJ<&Cdq=$B-|n= z{yQSp!2K@dAW2d?%$NV`pA4f>A52rf|1o_fbaeN^UbT_LlP@4dtd7c1!f`^qsNOzu z$uWM!`4gLA>}pfkl2Yc_2R13`kg0Uc))~L4#3b(h#SSAC=tMrGTEIQA_I{@S>NWyzdrMJp*F?X!)B3z>RcyV^q7)weplbh z*XXxClT6|(-hW!YmYqDU<-{2@b4hKXI-oviclj_{)8r+^`J;>3S}SmzXvp4Lja3dL z4|0iypQ)sWs@@eQpGC-$`jI1X%KfpJ$dmmjMS@K(Rz@vA)_lZr2C)8N)%ls+sNXN5 zBO_-i6a+I8c8r04IDPyCT6}OK6cgy>W0t_9U=HZz=NAiF3C}Raz_mxm&84NBIn98~ZmC@0tan`#(A>zuUD`<=nLk%;LH# zT5itIr%+T{Ibw#CI7#7b^j3A)me0qOm3yOY+ zJgcVFW?q_iZ{>-8@+3Vyd5;3O=_h2rFQEQp)U`$oCjsn5V1YUEVR^`m5A9cN_H$TZ z)%s!uX4;}aZ?LwV)KfGlCnTWoIsvy9C6VZV!n2=Lg$C`-Mv%tuc4H)N2)9{_xbtL1 zw({ide}kkjBC4RvTi{L9fBd(Dm zT8$&I8=PDH_1~XV^bcchWojQxvd|*zPk4;b^O5a3^I9D+Y}>}=vznkiB7xRr zweiKQCK7odM67K)|Bclo6^BwTlvfVGDC60kIk{6$PX@M`3crUj_NP@kq({G|z)qLO zaI`kTc+xCXqu@mDu`R|T&63H2X#_-V&Lyok@^-6c{7+m^N;+#9>+e%Vf6FFBXCVPV zrA?v;KuIU8WsRlF9i}x2%1=$p{H6dr!m>9_H`nlS3kU@z4V(p_1SHr7(0^_ASSY>A zNh4EGtNlqT&>E+p;sEF%XMK4a0l)YvW6@|U=lHXBK|8Gh)1Ap2yhDB7_1+4#A@gJ( zw^G@gYPNj(c@}ZQ$FG9SPE#I1d?a)eCS_i(y;I5;Dfqr%prDI%^Ce%D%ljKk>{PTG z6QkHrmjVGrJVP$-PnkLEe_?w@d53_Pe=;pIO<@AXbPBjxF1^W2B}}hza_q3c=@AE< zDSZ>q=b*{;S+LUlp}7-d^WBxUZH!^2SI*^SGT>9y2Fx+>Q8NcJmp3tZfI{&nJ(7xi zDQl+7bPVf0TS~IBSJ$Y2okd$KUCLK68}p}to&JCb&Dwa*-yrsxvJAm?32^w8b7|8; z#@csrw>s`^fzOZ%uOrK$PoKZYI$vs|pvUx%EJdOp07j}(4dw_rPsG28!Wm`~JS0Fu za$4pmGgTB9)E}z!{T@Zi-b1AQAayWb{>b4|M(r`ZuyKf!zL~;@tAAyMW#fWqaIUE? z?kMXY(j32Cig(3_-yO5ccALSFgr2@H?luF&z0815f`9;rPC;R9nNnpS%3y{JRBYN9 znjGrCwlmbgn($Emvv%;R`*~=WZ@~-ZQIJ&xuGTX!ARr=Vl25P!Ew!@$%KlGxBtP8w z%fIGW78W0Wz5|9LC*a3H;1_=6_zL##;*g*%Ad&Oa2M zz*;Z2?Bv~R?p-vac_rYb%z%xdxLR*#l{=?;AbdFsGnEL;P_Us3i>6EdmKuD`O-Pga zLW~r@xJPO2r#0K7%eg%|5>L{@?`TS%W$&gk>JVo@GBHU4h@Ej^b}K$|(%E$y$PIK# z!0j&G<%ZI_j67X({(PFeW1^WY8=!l2$|=>GDB1L&V|hdTxd%I`I`#%|0J(Qm#iYPXrwn0vsHp3b@@^NiZYuY* zx6C8JnL&lUEyX{#XY-*rx{W3~zBAL;c)4J73&>P*WzPrOConIwShoUvUayv%k=iLc zO(&=bDVtV&iZPvhMS=0KCHVi$cJq@c&gTWCS5*o#yHtI=YJMw0_872uxy zY^wTH=NZs@7@L%VX~<10dk8cnsBCGcO(K~0d0+2Z-klWn>C8)d3HQu=JOmVpsE6+o zoR$%=O){vkXb5rtB01D z98rqx!1^*|IfaK`#0)=*|M5`7;1}UooD~Nl4OShDN4hOiCCR2@+yD$44!|gsygeUv zUjYKmBvrFJ=7Xn@+yhpRA%$)&O6(fyvAadeTsWqUGVcl2oID^ffM2b}KXl>WMThJA zMQtfkmp%%Ievh2^s6U7ycmq@n3`N?A(Z6=#a6Tlm5KuW`HL?#3WuQ_1N8yAdMD7Wc zD>ZMDQr4cNA)g4JOyXEXar>VZ6$Xxi5R~(rUq8}{oCu?!c)d`^Y%M4vRGlP#k3sW$ zfW_kVgp0bM74x7w8yT$(9;Klk_E;n9P%gs>+Ok1EJK}r}Iz?}A!zcN$t|)6F4#}Y& zhsf55wqs;Vn$((i;I02b|!;&MgJ*obxe;jAb^_5gpS9%yKL;kg+v_jPi=buvK~ zS4BY=lfYIoI7!AhyMxuDf`u&5%?o_31kQoLaXJ^=|AbBgkGCs@cP)c3iK-UmL%1g9 zukpdyG_HuuKM=Tvz&8Y-$wbgJJbjFfo@IeY06}e3wunEvhzOdjBD%xD6J#8xlzWV5 zbBxRlTSsVP`5Y-eW26gcS5$(R&~Xr8lRoHtM=kXO!CBFiNb}+Fb&Bc1DIf@dj~AO=*E zz%e$aH`=V;7F5*-&-P~vFQN=j3uq7JV$7o6vU!fKqO@!;gsOmHB=D6eaKsLW_qJLm9=QJ`-XMbiiOk4W4;4Jrr5z-7~dOSzG*iDEB7 zc0W#HlU(bP4>v>lrJ;A*fs#ss9)X}Qc>Sa&>Vg<>n~00FyATkL%Qw5gx`uWSzu^eW z;*%{9y9OCutOkdX#yCu{f9^d!aFIjLxXDCm>g6M3Z-PiJQ?}JXmm55l$b-a;#Qtn6 z*Q@Zgt0+P`qU{ixV3l2%f}rMiEegHc;vQpAB%Yv}(vpvoZXAVKe4#+!2q+VmbYGwZ zdVH)Uf=5YL4-O!6K|nn)M(m;mN*whNXEwS3I@%$LF#;0$pz+5PeCZYW^wXzDz{|tJ zCbisGuvFo@s7PU8&|8olNMHjPJ#X*?9qC5|OT9(y8Ksl@;0J7R1VBUQItx;-e0AaN zBY|ZUu#Q;l`Af*o0Hh69z<_gi$%Qa}zOYpWmn$~dM~q!q>B&T)UWIH4R&5f&djP?n zaq}sI`z{@aq@gQ!ys`=Z`Fo)_fHg zu=!Q9g2+*A$T!%0aEMv5uDWlZDp+~4=68%dsj&?6;o;U|E;}Yc%D-BRdUMLtZ)$_0 zt&sSMi)v(PA$0!%ns8l(@X(HyP*-sRa*%)q^&gu-Uj{>Gpjz-!y|{Hc z4$m2`|0Pt5l6^4dc0ZWP&C5kdYBo`^vUxegL(;gDSK2^?@oKjw9Z z%+to72QYBLlh{j!9k3uj#zsJUD6Ld+FH`4e#02y_3^Vt=sf_zX;BwT15!YLa0q=>(74i zX+6Sml_^lxwH_1R$R$NnMRsbRv4f9LF3B5W8g7od79rdTVF~#1^UYW_4M_{e#xV;<`-+b-;9IVXIXG_BDmHYOzj;p0*Cmy zV#Xyh2s)^`CN9|9kO98oIH!z_=_q^Saz)mZC|r!}|y#$?C&i)6z3vr2HOygb=ZL#v}QM zN3O+<6xW#-54v#&F z8*9okaUU1tI&9qBI##wW6)`Y|C1_WuUzVqK>Kyx6`(|8p^6ksScS0KPo>mj3VdI)D zU=FW9=dBSP&MIalLVGv?T$d0?i@@q0@6WsiPLnWjS=8QJpaBW~;S7mSwo`7Je=YU} zZW6vBF&L8vPG!BmD*Q%`trnK|3{g4`=>aqOf$x_#Jg$um!orT4gXX=xqHXL**$JeX+Izpw zK{-$~57euCjmQRfy#-&peY%>`>FdT{6~UK770Ev?8RDi?+QI*x9~gs8I2{3l_&@K5 z?LH+*+Oh%VbU;;pz=k1{a;0}d3JsDPg%`~OkL^wBs+Tl zGLqUaDXX#*|5E>r;ni=AV1&$HrIG}KNCmLuc184Q;zXmXTm^Xs$r;c_!}PW#fR6rm zdWoNfPjOud2W?}&z+qv5Yd7nCb)Qk)lGcQi<%GDTgcRPZh8+;;oX|l>XhsjcSc%gA zGe+upG+cB*rSz=Co`_x4w%3)x;(PZAM?W{L=$UYB;Yd=s>9?5b5i{>yLo z@Q2Mu#Vk^O!5C<3ucYs@=(i8I$=E+u*gs}fXfI;oFQ091f6Fk=Py90wjwgYWGQgzF z4i|A};UPH90q{ha-73nr;!l3W0a+BTLIX}o;K-2_lt39kR*p#~$XjB0D4>5kLEgau z=$Ch-s3O#lbQZWyTW3od$0NnuW^D5m9g8gs-Dd5tsULoxBz9oVA@A4sy5E>Uix~a?tiG=}#7f~n9+&PguUvl*3W6oCH+^O`4p*O8@9JI9WX84qd z;XLv|->23~JKG0Uh{`C+anACD$4;0p0w~zL`^fXB&WqM}udV^bc&JT!z|I2lSYrJ5$?n z<9jK-0rOXGa2EV4iI^0&?wTqkGNM0UqK&4NC%~d>PnKK?y;LjpE$Tp@g>0%qy{-Jd zn|S@-aN?SbG*8oUisFs>(`}cnU4R^2G5}EYS=?+L8D$4~<2O}Cns4MLT^~8V$-duL zGW-4haf+cF$&cSw%_o3hi-g!u`eiQidh5bPRyt zF&`6UqT}aq=UhE^KcjmDR^EOxS{-urQT3&rU8zWzC@`4?lwm2{B)E$_pwa|R!(bq7 zt|WRmfz){FL6`2)xDDRBZkOR5d(7iWRN$4;;B=XsYE`&-mH?U#m$*Df==0{<>WY5% zT60cM{_-RBVCZYtlzCLjPq(*Ig}d9c1Ua|niywu{e;djU>()OdKh}(EzT7c3|3oQA zuW+0?=#rSB72~4*a7^`QuItUnJ1v}``(we%orli6^Vm~18(oe>!EK4ux-Os;2(G@= ze@9v|)?@bm{GF$vugWHEWEB74{N|Kyll<^bvREcWo&kU~KBcDlwkJ~6oJj~lF%L>MH*1W z=&g%UyZ0b^I>%<`Y=$ivDZgiMd{{16tJ35?!M8xsssGHYFqtw}BUo|FV4Vn#n>;=C zxc~L>?@_(sbVb06#tg}*aj09^TH0v5gc5RKGtqFO@{7gP)0gP)OgE1`)Hx5hHgf}m z%i2O4xt17_PCvAEQyUMO%)y9`90trqDN42{{hu{s(Gja=!ZH2H>PeH_rVE4~2kXlQ zY#1L})8cA%xO@aHVPI3Y^GdZJQqzlyMq^u^Pj&<&7*rsNL6(64%PKSg2^XOB%)W}! zM%t;=)+Ye93{CEGmL()&c8*O@3h1PbOQU)s2(CV7CAlx!k`uHuk3%jZ8^b+QWumua z0Sw5zJ{Xbx2c!T12z#W~o(*JX#;zcyZGIAf-I4FElps%7XC@H59IQkA`ei(0%#z$q zmatWij^FGb&XYTBg?YyAF%_m#v%Gcz-~0luuGibzoeVJBW_1AyZf1F_U4?x~C$-A$ zL|b`guuP6uf7rMNc+&3u&CfIYfwBv^zACanbf&}JlkfQKk02e+fXAT1#)i98K;cLA zJh^}IX*IoXA0Rqu#iL6X+6*J69Ds>&w-7oWu;FkzR!CFqT4>Tsxi7<+0(s_F&LVAY z?HdUIR8{-r)O#zGQPR*xJNN4PIVHrDg8z;NPqw9B$caaR@Q|SQfF)3QeC#efRGf;j zCE}`zd;?h1Ig|b;{SSr1HDk<;W}5?~?Qwv>pu2Eh3-0z&)EE1ML2i5c@$x!>I3G-V zPAq#`Zm}Ngn=^+#fBQA>SzhMhfn&bh0X1E<}7e(Ga z9@QDjQ*1Y`v3CJ z92lwxwNA`E7cNbC++csCFjGhB<}gAAPQ+v;9haXHPus68ke0`g1?B|#rO~;$j(+ak z5^0vu(dm(DK~Y86rw(#e#IbX+qKYXeR-co5bB#mF1%wHnyL4v`D=tS9vw$9Q9>)j- zJ=-lzNvGu1))5{&mI5%9q;&PN6R(=06|DJ~cpd&e98Emnw?oC;9jy)tX{;Y@#=DNiR);7OcliOrn#sfrIT>>{l*pYUd!f5N3I zy=Eoa7L31nP9o&_zF3A!vWChri3ifQ`<#qGzf@#X>zcV$jT8lWs*_vz?l+t8)?D*VjS_HtxhZuN+@_SB9}DxIOf_| zuEVL5XOGn+?64()-Pm2@u;FfEYHkb z`m%blQj;?uw>1fu@$lWomFP08fOatOmG16-{0^5DE%~`FJp9ZlPLf!b&C8G4<~6Mt z^2W`zG}VChmGd)=GiQE1v~_nbRAWymz~T*aRZEk_on|2PX_|^w*^t0VBtA8)@2r*U ztk>;h#1}2B1C7LUK^Xze)vYg+HYGc1?yx_SrL9v4(;Nm|K^)gTKXnTBbZ$Eo>pm}w)mchxCv8ZCn(U$XM+srqPm~`o@Iq6)Jc%@PpdZwFyBNo z^H%p|`I+(QH_-J&_B6F+vzf1|+Umq>vqtXee}O_JTOA4lVbN8b3Xb_hP%YmTn2-0VmNSujz3$ zqr<@0VyN`m3BMH6?befErx~)-T+-59t<%)V(u{{<$19-G>}t0=ju>+p=# zH7r7kiz4rp7`4=OOv^ftMx|oAjt6v~Jl}mPsrz((cVI<#P(yccXLrb8_nDdQ(C^)0 z$ewV)o(P4WvsyjpEPKwo_e2KtM4j)skkk{M-*d5|C#Iq2QfE)>U{BmkPyF|u%SaYQ zkVREsB~(~BN^+YS;F7giDM%c0QNm2KYi>l;`#g^GO3pfUkafSQD7rsKwN&+bK{3F% zo67^ZLGMkYtgGW#&_%A1MU(IEjElA^WI=P+mqq7sN#D6buxVi|8oG%BwH3QI1#bn| z34+|ff=Z?zYdXljVo(wxO5>}=;x@S)tL-vqDF8{qPm<=`*4c8=N`Tq*IM4pxNC6B; zdk}()V9}}s(=r>dqO~`U*}h)72;Xx$;Y9*mzP!2s+e>A>?3lXuY_O1&5D{uIXfAkqvj=c z`Ke%Bpfrh>1lI7C-Qm+p)wLOyYt>U>KyAf+pkw!(Wb?B_j*<8Z#XLBG~pEq6$e(l)=T=; zfSsv$AD-{r7B0~(m{t3THs+hQFxd-K6=m1TWr38}JQTFvV8qNjfQ{aQU6JNZt6ZjO zSKY~EqhL&!LkJ~snC4F$a{AHT5pwV7Ff{|a>*_Pw)HoJ>g2l&+2p!}mGY)3f9>`b_ zkJp1=qu7bDGW7po72yY*T4*OD-^i<{cpH0!`C1=1h&w7pbN)fQqt+X0WmB7(mgVn~ z!Fm&5T$NFfd?SFh%gU4LYaMY0=iB0W*4?vK5+ZZh`zOmWtU$1bC;1%NEB*1cflh3Q=o@?W>|H42=6CF!73@l9 zQYHq^-)0KJe z2hGR}`D)2~iZYtDfVgDrwMQ!X7Rp;rf1FBoB8e&2J|1J+4q38CHD_u2;_%O;Xjg}v zl7^hBAJd-mQapi)P5QVxFQxO=SQK%vXDIXP3SxO?6rcjl+=Yo@Uf>9p$ChbHUOoIlDtqD?&B-Wbd={*^eI%nGsbA{wOHr>Zz7#TP%=gDM z&xOxBQv5etKTm~^WYUvcx?HXTp8#o^E2x;caD=^Z=!xS?fcf^y1QzDxS4YIR{lG@J z4EKclWfPIM3}3$Iw7F*5jeHcD;=e&oTB5u@2KZ!D^@;QOPZ0-eX0SD_6R$Rp<}yBK zkta4t9wS1Zp+y*#HYK$)$)@z0(nnvk(k#h-b$U~otk2Jdl2p2}yux{VYNjN90F#A^ zc~`QIX`1loIUeV=n$~|(F8Jg)8;ku9rFJtEWwqg%|J}WmMe?%reakAgqHZGF1&7yBQ2@$+Z@2$+ucJ^yF(0gcyR`~%MV^11KD z3+P$}t@5{0`!q4~r(_j7fk)?Wda{o(xx!qg0<*@CO1w z%dT{_Cks;eeV)MmU z>$;r_ZFUm5#12~K&X*opzq@dpQhYa{G+J(HrYv7cN$ILb0yZ!wFUotd^3oqW#k?HN zmv?Seg|5lv+_e^$uc{s8-0m~p9(;sXJwcvC3O)V#>dV9DXzu0O)+b_L>O#_XEg5sR z&v8ozS?*qG7<7{$KOVkU7hJ}Qy6=(TMt3oT}-)#fJ6n;Wuh_=Vxp6a(H@IU2=fUF>BX1LS;%EyTFY>KL9`sIMeS<2nmALAZ@ z*hl1JPrgB>rwR_m2G~1jKU;G8BMjosNUG17xjl5)n07s({;g>GYc8~=e|(_ss*EU+ zg82ps&5g<$b)10+L%yvg+qwf@y)c)pK3znAI0AS$Se|XLw*36DE{d_51PCM@JCT6u zdh=`DDKO4?VVEZz!Hb}OTK@6ol^jzbe1=H@BrQ9fjb2vvZf{v;2{7f7jr;oa+whk= z6%xP%?EgdCn}|>e5zB87DR3ox4W2Y=b6fGK(kZLRyQpS>f89S94lD!&B z5vs8iNsLlasRZa{=Ao$Qaliw%!lX# zsoUZH5P%r0Bg1DE=w^8Xid%$T8Kwa_cyu|G8Vl)xz@a?^K)2Z(0uD@u{6RajVL+4; zP@1utsOA_yx40`G$+1v01;b0~z5$5s zj!_}&oRRF|yDcdfUD$=kvZYUUg|+x|N#Km9g~-7n<*igjETV_>4GLslWcpEqFO0j0 z$K+}Zr)G8q5cU>!n4U}elAXNGc7BKr-#?-*;7EpH;AFuMFJKD!*Tin`56`V5Ap#g- z0|v+rQM<0-jN|;pyZ1}&4RklhOpFh6rjqOh9A4-?L;GD^MnaBNPvkaSL7COM0MgCv zC}BIA;cGsq0h+@1yAox(=28|oK9*s;D>V(unLip+ z3{Qfd!qb#D6`iB-Zs!!3ER*>>jr!rLoeB^8w*DM(POh^#3U#+Nc_L*ZJy!zk;B^16 z;exq!O6iZaeI`YDgBL6y0u*kU*{OQxC^5cUPkn6@c35uT1?38nh4 ztAc#DLessx@h~m1Luo`e)DZ_pNSW#~k_(p>rO0mB9dzG9O}y$VTJ${Sip_0uGC+*2 z4a~9vvd1#&uOJ2OlX_iXvoDlJ(iC1vlF%AN+G#E!JZ9him-jtnCOLVwfk+IxyuWfQ( zL%xmu_TGjP;7I5oB`^huF%u?x!f&64$$B--!){?ng|R~Av0{~gw=%gf4kOMK+SuC; zRc3j~EPQIjmq^SI?42!$E8atMI%3N`CZ)8H=ZX zg^)4;`iNM}`C=NJw6X-@1b4T}Pial(ub;rOGy@+V}Xu9jUVL=Rt8g-ovY};no(j`B9}?J~X09K`<^t zQ>_c*FcWgXN|C;|v6bMKv}_f7QG83%gPn#Nf##*D`AH@l9Jo+(yvm(YzltYm@G9M> zVo!o4kc>&?KLDl!{fqgn8=t2}Djs?}g>L$faRk3RXWR>2y7J3dB~SL%K%&!fsZ6oz zfI-X4g8t=lqu*c1-}86gboxGILMf$SK##HO)pV5t$x;G0X1>3Uz0GL#3qaVIe z*2bGl#;?@dDtrqyyII8DTxI=V05F-E&Y+Z**FdDUtN|QEYDd>UF2((p_yb@%zkq>* zNNo?f2>KtS_M7Po*#CP-?ag>&3p>Ikw|K!pjNO`K>#F>|)eA@K;=csLUH?XEH;b<@ zM1OTdJpVtD+DQq&$%%!K!0=|V^UaBu))M`alr^ARwxX0hr<7=D;q#UJ@#6vIyp<$( z5fxCjCVGTq7bc0c?}jjw0)!EFyVQe(Q%dzy%6inVH!5i-CS%%nuToXP(SbW1N>0So z_lru69;uo>foc^g{OxXbAp&RU+dK5rI@VmiJWa*9kU{=z&Td~ZqAy!A{iS|-KiXHA z4$El{?P?yXH)R!Aukz6YP6vm99Tdg}2>; z9*5!_MT|B$n8tb?hhsRmY{fgFf)HvZzipP76wpQmK2jpRc*__mKo?-b$`4rHQAW6O zaY|osKPr+30btlJc$Y!W?uZ;d*DX9Q2;4Tjf-5v*(ax;NY2-Z$SRTmNMBwh5J)WFxbzw%DWWnDAr(+PD@6YV(o~4L| z!nT0Oim>=iBHxabW825!E#t_E5Y;6rPR&sK`IBJ31PV{xrg+o;YHs}@zt zJ?+-Ao@&@Z;1rLB;wJ&BAc~9yzGT7FiNGWqXXSz4k(?fX(b;8kM0SwjF;oP1vKQJia-O_Zy$p4~h zxwrI*K*EW`oB)_GMcXLyH%nAcBH1+dX!2!L7#V+t=FzHz_oN{_>Boj%i@&ppb*>a@ zC*Us=@y8E|Px(o7!Y>7p@yjXVw0{@6^TT+DN3Z0=h4V?*nt;FWb;r&6~c>Fd-!>uiZb2cDxG@!hM+x{Qj<^@+p|u3UUO?hH2^B!F zI6L?lLgj}L(U7Lc>{Y9GCneyAB}~~Qsh}u-7HW*mCufX5&wA*q<@%D0AEF&O74uM8 zkl@0F-6nfLSa2;HMTs`?19)JPj)j^Z9C+VhCJT(>eRhVYiF)$^=f&aOXAtemWIRG| zw9C9t+~TbGHerNBw?g@?)@yZ$>ZR60-gW&*_<5J6U1(%+E8bv3{PjWcGlwffjJv}Q zcb{t`B%ke$6ci6#z?8Ih(`0)p6!U%5dlI7l%1d?rb6(2$S?=LyJJewLf9Iv5#0y9N z0bsIPc!sI3Dszag`U}8h;Y~x-wV1Y-OVCA<+IxX7y?+2qb3$|Yh*H5mhGyi=w8%S} zeGmUP0MpRn7jM#{B1@j*!(Ti+TsXS%f&(J84|ngr+FPO5KXa{rwyl3INa5}5i=4j8 z=mpgL;ek(yeT8V+*uCd#*OKCiqS0-c>rDd+3*mm@==V{wa}r>&Qt>Ao!4E(H%@#lk zSb^;SS9cAt2c`_(HMG3d%*C_=M|3CPu5qvCKq4LkfbJ8im>?|J*gE|FLE9_b4AY2!8MDTjsIn*Bx8$&%bXD{fo-<{Szw=^}6CaMQW@^ zXmxLY8~5Rb=di-6mu-<=;7@qaOOSDAf~J>1uc~v{dDeuhPDgC_gTlI&A0O_ zOBYP;Jbt`?1L~p(PPIx~5n?vC6pDoLDuqc=O9;~Ccu^;R@5_>2mEJM@=RAZXpjC-~ z?hAEK#FykM$5S+wX2w#tn7kb@t1N84oUGMa$iy+7NP?c~ODxtv+dU(so=QAoI~6ka)2Bl8HkZI0O`E;E;I z|7Km4Pk~8=@o&kcTksFMp1j>S>~+Wjc8e`uplp9xjsJ!S5W}FAeJgX;Y`{06?ABrR-}S=^cHF%MzQiWTyfoR2fdOs=gcmVi`U*WkoIwIq z^go*Ltk!VCi!p@l4vG$}!DI!-)LDK(g}#q(c9}bXR|&GEa3w2VlcFf#z_1VB)iSwZ0_E*M}n2fH%T6XfXdb-J`ko8%7qW)5ntyxgP6IFB)-;pwl?&|=J zJOuWb2pL6F3pgPU0JophrTdL!P_18*LHl{rbVc$B{u|7%U;?GfPq*HJPZbD6n?w5R zGQ*QF3YBGLTRu?}W2oL5ro&H2i|F1*_{3bIZ=%}1fb^+(b}YfpT;L;_Ced?K9wPer z{bpT^M7*WUm*(D`Aly1ZZA^1oQ`OumxvwnQF}^xTUhW`3J1Ykq6;6Ty@>#sh$Rx+y zwZbu^KMAu3-DSMLy+a~9obFtmvm+|LMEY%EuX{fQTw$i^F}>4+!#R*Y*N)-)HYxXA zpl8r5Tr+oXCD;{#s>h1Vcd!$Yv|^#(iH4h1nRN>{i*zVu>dc5LA!E`FkoPNICEE#2%;oS&f&dDwg zC!*j40AO)tvn~etZuuJ1Q7=|E-HuYQ9o$ur=OBKU_(XHZ>vulj$?yJW>h0$?ly{w_ zy2fSk?JB}`N#oK5&4ny0HDVolTvbV^_es}Q!ouj3bkl?6!gyHZ-o8%<6aC(+Kw1IT z$fEds+vN5$CsOZw{b*@wBd|IjsZM_Qo|dWbN#9nZiyp6Xc#MB@{w@t6$N@kcD%>d+ zSIB<(?M;(GB230?qdjw#aMIM17MrlUZ>t~*5X>sI5GN09m3uMk?na%7Yu}gIgWyOF zc-W=ExUm3vLWFm8qTZ zMW`?qAG_gc;r>6LQ?Lz%-40W`K(MsGQ^S?FeN(!vKY1^x84cI|bEAA$l=fZ%!P4m> z7ik4Ao7JBZQxxfT#}4WqmPhwz%zbgbJ9QTNY>`x6mkA`j7;1V}4~`mUx^^1sYOOuJ zeg4H)ubUMo_#yZ2COXdf$ov}aak^h$@M6x-=)Vq@eo>qr@%~r4?W3k6!X^J>u=GFf z8pO;8eJ7ljuDsuv(jR!xf4+a|`b|%MQ(O!Cue-+Y89V3yb=Syj8LIdfca2~5?(z78 z?iZiUD)x9^tPv8tFg!!xXMt83`Eub!!uhRlUw#NxaXdAI0GHnl^N+qbCl01@BPbS4~I8gGA;TDsO^<8%O~*{ zXPtTL!vl|24v`SVp57J9Pl>#@mlC~h=0yj8Kl>d3n42pNH-5unEVia&8|wJtf%?45 zo2xqoyn-SnH^94w8m*1U_fsi)Z(<;{1gjgWu6qnaqasroheU^I*kOmz#xO5S{Eu>- z1&#-Vh?+hQ-C$ssK;_E71~2h7oW*k4SOrNtHAy`PQy)U!=bWe?0s{zagA8_rF9OG7 zK;cA;;XPba*j^cZKuZ5?V<<>s?szO%6}Q@FtGK72^jfacH%( zs|1~Tkfcn5!pNu}bleIZ7b28bc! zH$jgsJ1h}`r>C}{L4|(QkpcgsjLFzdj^P?587h?OACCLU1oz|te=Dsl z6Gj|nqQp5sdaN;o83V!Z(4Pq-ir_ZMf?y$3n+-b+XnwCmen)GPxd;O)G;H5qj$MMT z+S!kQeV2=2ClLyz0M1Oy!xW#x47)(q0VoRw%DgU!wwDM7!iG}uXHgssgo5Kdp=}UR z2!=_54#BVk9>_2RX9FQBy3>-tHv5b{Z?Rp2SZFZtfd|mnnKpNt(IYVTE+~>h0Z#72 zEfKAbTk9S#OsjAYi}uZFqvaST@3F{1BiKj^89w+HdUym1Qj&d+>k%gsk1gQ_iGZYf zbkKBex^SL>l)aG@$=v`rMbMwtgQ*h$ia%~&ZZ3~12*dBtcpBa%q<6Y12jZD`UQz3ZU#u`QtH*4|IN!1xFgNDKzA~XW<)l9no;XP%M=oHt$mhwl!h#owEg(45(0sj)Ap|B(RvL_y0*ixw(DT+)5zMME495X zwSDhu``2sP(zjn4-X2<~y3)@D7t{dI+KU>s&-B2d{{N-PMgbQf79#f_HJQ+xy*3;eH0=&i^x1_pkB0P8lRM}sFRr=~J~}*W_)C-Rihmgj&oJ>XB|XbVRQ&Op z$3_2!G>PomJ_~)Ns=KFXkKEpKfo~f8UsYqCeJ)D_G-ktVDtaCA)O?=L%C+AAqscIv zglA{2@yD#K{NCq2b^7B&dNJ}ZO_sW_xczimQ^4ea?oM!D(2zL}{2Kr8>hRmT=?eF1 zPG9};)Dz|Rk1cHnNx9!|tS|GWC4T?-@Y2;I1-Io6t>#a;7wQ$rU!M97dd-QWO#}KN zPrZ*C@x)qhJRtrpFQq!jm6-&YfKm-B)KYgVnogXJM}ql3M!_xRkY&_w|68 zl9O@~&L%vD1yYopcG+6^F?pg(g1*w6oOhrN(!bN-;7Aw4jNc7WT3Ifg8~yZmL!oS7 zC9mDOwxPG$1~}Z@{zUgZWej0j&$doo}! z#}vslW9?w0QQKE-KU?f=*l3aeFFfQ?Pwy(Y_9B?oDpvZRBSik0M4ib!8tlv z+jM%+WNGacDA5`fX?(+z+L^)3)f})J0}zvaHi*l$U%_n-yb<%g2>>cKa>gg#+QdNg zTYgfUtT4bZSDP=By0$o3z{4%AZsfdJ8kA_rG+wOK&NQCpD%%0hJt^@JpsfQJ9Jt<% z>a`^`l{oJ19cGEUk~08f%Z^Ez=CK#q*s zjJfnE>4}D`3&sVA!}(Kae2o)k0f8S;nyh9uxAY|c4Kj6ZAyei0KvIw_3M*;@+fAC? z;TL9ccANnKRE8waKT+t=ZX4sYz<>aUvU6#bINcVZv+H*Ij5oB?rmIT$oPsSxhQM`& zp>}tZNn0v90Ajqs@icHL(^!bh)YTX?yE%DKm!I6NI#j*io!rUC&%s=(R6ZuX_Y=~K zhV?T(me(_sp{ytboP{SQLYN6#O4zrhhZu;Dv2hS5ATv@j(a0vq7SP2bFAd#Pc(S+L z(6+PZc*={=4=!@L{(OmjLJr;loi-0`=Vk63hvl!YeKOM}T&}sj#Apkioe06VWO!t6o)mJt>}DQ{N*% zbc03RH2NYF1OG-JOxMjL%uCJ)L5XQGwXACDixi`}r@D8nEdiLFhi=rf-B^GDz}Pbe zQ(Cxi)=jy23hFId<9_Uh@*TQZin73g#--QZn3FS|0f#U1_1#gF&igEd;%{O1TzRu~ zH-@yXN=-P{SL(~WJg-$6b32)rA0+;SaZ1PM`TK0l&12~%x2gNG59;~>-aR0sDXTSs zgI#@~I_6}yA(ZYdI?*x=?hD>E5){!aZF!IRPOM+RT_CNtDSdG^w3K;QJi-y1+b$hB zeNwpV4XiHt$kj_CHJO#!<56oECQaz1*Sd7LvK*p3wkm~Qi=C`R{XLYzQ<*mAnVS)mj>ieo}H?M9zfyh#E{&B4yQ}wB+?<@t!71?&Vpq^cjvq% z!{h$eWIB9Oe>se%_t>dig)%BrD zr+d{0Ud--qU4PBYxL13^@$13&>u;L-@7?*M$$qWBWnu3#|L2-)+VOkj`(Gc|`kNlD zzWC2+viQ@EC+0dAGA?XPC>%H+DBxNOi7D3vv+0T_`|#IuzHR}G49-ht=3Gk$k6-$z z2Q9W`!8xthG-vilWCvYeDxDr39c@QJrEaC@7R^jwa9REKsB`gF5^7dW@4U`h-QX3O z-(PK=^^~5rpLNUKnDxj^X|X53_RYmBHuAdfW5`?lTKVPk4 zmqQ*~6W%aV9fG`WJcvH>pTF&7jK9psT${pXv1F$4uG3W6H-0t!E0QjSVPaEGe9|OqJ zouMcCDxgI+25s%pXOcQ)K2c<+$=DCJ6D^>I9cN=clYAin;zZ-=38uEy z5}zg)VvIjJCk6}>4VT{->^Xt^&4L0H0Lq2NOyX84CX5`^)-YV44{n7bJDw}JI;9YB z7OAO%gmTOsF5}X3_p7kYeD>km2VJ;i{AC}xZ*MdjM8WsaSZ{4y0JzkiixDIdx%Y7M zG^Z~^@jp}p^?G)fgXSe3ilFdwiMUy=`N9$|U=6IG0m=0Js|+tL7uQX|&*0Dah2uQ) z&@hJHR<@! zhLPX`;dsO~UjRbY~^8(*qhpk&hxn z>pZ*yUj8A`eq}4ph&vtWOkJU?rY%CDY}he2RGpA9E(xd;GfV;Gon{n25%LSLS)=a< zt+YrQHVO~a1*ZqxOTAtwS+#)sNQXf2(A}cI<3z+^a1{*?&Xl|7Oe&a&#y%inJptrf zNm)i`=I6Yyv&vX+8jx5CH={+?R775b10qDebt-P45hr91T<7qm?mL~W zdl)NrtP?kzw_kA>s_T1pDj{9EC@0HJcK??g3LVz3S3n>lwiAIemVwSaT=p{Vv46g3 zxSV)$K;W~~*r9xef6^%$>ca$prU6g%|9G6EOxy~Sa#lOjfR3bxWa&Q0Ps=Sd{Rs!i zsGoGqG$05i6v0^-aNrVn5_gFYpn1lO?a%pDneJ9p2%6Di6aXaMrUW0zHUK`btpxU` zf?Y~y`_neLSuIjz9{9(zuY!j46x?vh1E$Wt^7&pt{m%kjp6}K1{e}8fIj4W(On$=O zK5*G%0BF;oaO$-J_53KQ%ne3S0B|`#O7=k!W)t)y8Q4IPYY}APHZBg@i+e&Q!YLS# zRlF#2t($Z;fDZp!j{B7a%$>zD5hW(tf?HsAb6c=5fPaW7sPRtlIq|e@S;-M)-~1N@UXwiF8^sAQ?mdIGRAp_K8C*NUR5J#cC3nwpPw47QsR=XR3=LU#FR0Yl=aHgcV}#D@Ns*}CC^u(RvnP$3Gpda z$P>pAT2~hZfN|ED0o-JN$qadjAV~maUSPt+wyq zEwlQv5LZ77ZTHgQ(ZA(cjPPjD?W63Qe_3WaB%!Mto4bqul4ou%-XD7J)x5ncm0mqs zzh$pD6O?C1YI18?4MBhA-&d9Mf%9KMhOVBf*(JVv~`@ODfegS(bpa_0R)&6Toep-m^$=h+Y#+{dAt4R}gd;3i@{zBXD z1!|VzwlkZ~V*P4^x31oPh|s&YGr(zXEtOuQ?- z&3I`0vaAp83kccK=6#r5BlleR(;cnM_lr5O>idho_=~V4++|mu7x=5Hcsf2g(vA?- z^gl2rW24-9v?3LZ)hgpS<`MsWZtJc`=AG|6M|g5{=&){jOS$ zA5ghA_<86v(_O~}E~;}XD@bflSVR!urwht6aqr5hgrar+im;8U*;C?&s9DyhbY3Ix zG^wfXnQxi%O2Cz$4s4xoTR#2%+ru@l=YDMpZ@%t)xP~;oeQSdfc%z)BDpX#=UzYnQB+BLf0Jm-nZ-n9vnAB_e`QAhGv{Bz=C&4%YreLx|OH{gwC7=0~#a*QqHT5@{BcNQHFx^{LD5&}YGm7AFv8KZVB)i8Dn7bM6* z>Zp;75^Oq45EOA}c!$hE763^jNb?G9GkJ3^9iq}g+v)Th2~cVVG>QzI3`eLE!493z zxR|CINw$=MG$;dr8)%y0W@+ZyDNd6AwLO_|VKX$T^gL<2n-9rE37|;;09sbx{UHXV zF%)$s1~6^UJXbp)&(l|?yzJ?@SvyELJy*Q8)}9L3QE&%l%y9{fXHIW8`~lz=BoeeN z!EL|=g0hkx;j*>vVxF1QxS7&}_KTX|6;c5fphAQ14o?M>wOb^rxe3BV0B}W*o3!Xz z?uX*@*^TzAz535pGO`pTuh;@9-Z0203FE-(sI8Qj47wV^@4R$NdbuDo(jTp@>Y!q^wfAM7N8@=(VLSF(42ISc!zX7aGok^GrlBdQ z4dNFQ{37|1RpTu?v1fa~R;iY}&P7J4#Q@-}ceOAF5)6Q8W0%Y)vSmfjd~IF3rL%99 z>Hykj6)`Imn%IzXsB$<-2FZLKdF?fU^1IvRS?}AlHn&=&{YeN#jpn`F8Oy^%_TTGu zzgwPr{bG9U(V7vX7@Z#qJEANEp9|3<(A)1^pwu2&7#lAA=3ZZUMDBQIi}4jK2d*ed z(_0hDyujmH!ud!uD*O=#bgPFdt1x#gydpEsNjAwXkh{%FV`#>P1ewT(*ZIQuY#vHW z#0|UOL3U`2ek%`y-l!}I=LKhk%=IT&?(5d?Gy1p?NhqrLamRPQ9fx)Rx8yxyF0EcY zD!wN1SOZNIILtk|iCkkrZOXkqzdvFn?+sTWK;o4h#;OnMcetCd;3`qx0v9AZlv!5C zrP2=Gy}#O}Bgirf;_{2$Sc_K?|F$^0@Fq%j^{L*J7vMwW|2n?b{q%Bhn(|loZt1e7 zd`C1Tv2Rk<=;t$XMtyFD!)Fc49p(G`>+_q^gf3QQJm0qiG`YM-F47EoHT09vP!2AR z@{`x6(w|1MqtXKkrJhmG?JE8a$-LBNFyNfgt_L{ISjeoiw;!>x7EPbAG5SBrGY0nF ze^;KFgd`pRZ&+sk4S6Ox(EL=d|1Wt)z&+@(bz026x-qHtPf_51VVV8fm?r(RWfu8Z z%r5MJ#_#EE9`G#*Dq%rHUtI$ph-W1yG|_?#`L$e!)sc&FKYKO(om=0%?LT)vdUQ_y zs>efJQ#alA-(N#`Z=X2(oyXmio7d42@O)_+&Wcl;S8ix--*DPV-D1zT2akV#g>^&I zEfFO9ir&)9s9UGU*hMQ8h-A}|rW}Z%2hb_;k%S_uwDX1R>AW$yj35f`J0i4ocwA^j z>-%8{c7W7vFr=7nF=sA4DQT-8JC>kgH!dB;wW!GWl(d7|K3>q0_(3n>yvlAxVa_m; zr?y5+vMGxZ;;_5qogi4BB*;eGj70@ofi^^WOc{PDIrG}9cxP0M^biMb#fH->;4`+U z14KkRfIUyUv><`lLqkgGY-AP_6GuZXHDR`e2agnJjq1tyjmha* zY|&A3!Y5stWMjUNF;o_uyER$}jm@J=?@$Z2_fUAKAA~9x$s{g2OX>A_ob`EpV+--C+BpM*|Fc!ul z55m|h+#(=7SnvbPY|W8ukYh#sk`0dd9*?;odSd$`FH8_Y1dK;=Osi~7rE)C{a$#h^ z0Kccn-*Zt%5Wpitxw$8aC>N=`2repukmn(l=W38gF3NNDMA-rW(mO}|fEAkP=A!6T zt|HJ$&)1#Iw}ch!?!t}W0o!E6mFD2HRoJL!*xn!fc)G0;Ndyd%9^ z@Y_k!3U4tyj$zRPt^oiZ>;^(Kg1_?<_r3IR zC*2Y>KDV)q1aB!?>;o-4D3nKqg3L7@6?dr9c#x?txoWpg*xyDh{=N(M3*dv|Q2|Rh zu}RN40&bdxi>2PsBLY|gdV&QW7q)9RUT1op@leEcmT<36G7H9>>kofnPB2009P$0VEwb*bDH{|EOn28j3&zrYU|~ zTMnzY_)5Ml&9*-XOyX`50AbMJWa*s7JJ`aImr)iwI5@#A_}QXT>)c>R!(zTbKW#W4 zj0Xa-*+>Ttd`!v7u?KOA0w}_d@M+-H-sJ~H2A^KXC2Qa9f(OcGJSbQ%M*PDl~ zG)(d$-!95U#_FKjww$_+talTSC z63<@8eSU}hvJ3%BsL@m;6wE7=!T$m`oATNl2lHR-DLIsL_hlqXjRA8;dJlu*rQbXVrY-O}NdyS?|&2ztp@Jn#d+ zJx2hRbm*OAMszt-W@|lbUonq>9#}dEVPoHh3Kj+cFgoV_y3yOEy5+#&L=CLk3cm^k zszgVfPR3}G-F3;>9lDs4R~nmAfHw^6lzY?J3)rcu1LrPaH4^rGKJFELsA&bb-pJqN z0NPKioaFa8P<9TA*=)-9AnEFz%U6RpxP~8@=u|rT>Q(fg>BQ#`5?BydfUo323!@cH z=VJ7}CQ1q$?|9>-;RnM=x6W_z-Q8LUPA9IgJhzu)&F;4jzrHvBAH?oQQ0&qmTmB(- z`M`+R-(vS)dXeU8^8Y#?T8Dmd^{;$r&P3+*fA78i5xa&Bd&D%{3itdicK_&< z4<&=3e|oQ)N75C;xAMPh0v#_+<)%AF8qa(K#jb?%7V1TqfK9IoNi42FURAzt?T&ES z(NW#&4pISmHxTAK(tHwx&HM5!Qxkq3qtJF;v#GiBJ|VC=?(kgfuX;mffm-6N{rqVN zhf|N->+SNc83h6pXHsdKFWMd~O@qDHf|}mG<*&nHixY`=jUL7N)~E6mjxvqfXD44( zG<{^Nn^%4lFf4ZFsfYYndpsq;sCEz?T{;EkLt%d2jD2u^kE3ERB-8p5KIE*k*+!m= zwdi3`@x?+omm4ru!3*F@qpH#Pz)OJ>OiL^MCO#0Wv>qy?83k6FPu^wQZrqU<@s6wt4V=h_nx1sK6wW+ z>KRbYV>Z-eAwDEK-)d6bwy&zsY26tpxUW2AdPR8Bzv78n&F#G}@>4QRAm}}6#vkkh zPnC6@uGz8YL;jws<_){&nq?W^8ooVLy?1D~s_N-;4b!PdDVYz~#ARP5&sBCh0dtz8 z+)ljSsFMM)EhMl@Qm;0n5iT=VXR|e53b>-&?OBd#V|gwXZF&D{p__QrYL8OtP|(r~ zJxf<@C3!n7zJAhM!DPkG4cO^EyF)500EXs-y>f(cmS4Jo&vA(Jz7NYo`$PbenNb!M34RA3|PvYO;+97LVA9~eSa zrosOXq0T%wGLsth+u69tbas6KcdBWe4>kvZ0;y}Q1Lx*9I-vmMn%3f%p7WpR*DJ(n z9U{|3ze zhN5%yDyLfyv^8Y_mgq>*QypFXbpKpsL0FQd=nw%ZfToCco^&&UGGn|9@KiilLm4Wm zh~nOa@-@dnYwv@L<*Y=H3oLowB`!?=@Spv1Tch549pdF*FWX%ZSBc$S&h~}^>U2wt zD?L_R8A;n+)5 zv*WwTIklCm2|toeYd_ zDvOcMW!jpw#Qa;VG-5^rcx~yYoaagOa0>QTzk=c+2`^NsLU463%6X8R0Bz&QKdi|! zf78tC3C>>fnzGt&_*2Nyu#p6yNGymfwN)Qr39U_vnXirXMvre})GJHsj66WWs0`VW z9vcH=E=?EB5^6i?Zmu@#oO*g2V{=r*TwT&(-=w9&@0o72Jcn${y($0Rz)oKx*{Psf zpgcAwfVX*o7CdJu_ffPR_KnNFF>7C$JXfLYJgJo?ZB->|90PgeqV{fnnGZ$^FmW>+ ztld9Ux$`#)E*`9LcKF8~UQ)u;rNZ=z>P`g(sx+V~q?Z2S^&K9YwqMTvcA%X5of66@ z2rNm>E&d{Tw{Xrt`fWo~svi*7RKis{ZV&v$MBB~O;v(?zL5f;@Z+ZL{ z_nKc=DuFD$82K~%5kG04Y+7$?x%9%}`lOJ%PY+M+N`G+S^|jaeHKVhx=Ya_B_Q^C< zb*$Bd=i%KR2ED-dvOhk7uHku^l#-kT3@qAV<~@!Rq!XiDoBRNp^M0-}g_F*flQj{};6R z@vSbu|Epf)|3K{i=kuW}@{^3Bu$)776MmVk{}8+1@@-lMX{WZ}gAD{AYmGHr$waGm z+}r##^ZO-q3))TLF`@G!l69B?P}c~I!6||n_-ATRjEn#I`d2Xmui&Ifa3_5)z#oUF z3U=_feay6EbX@LeRt7?vE!?g#@yDVP2(P)AdM$aNiD@ndA4|}MG81FN+KB|A=jM_z zU%9R-8ZK+ePhfOpZ1WhuMRjbiwPMOniusu5NW9X=AjM~-&-2vGJ>pkrQp#kAim@&F z17AmICG|6kD<6vC^Co384sOR;QCRz6O{T@i3cHyAlLMCrxGWzMR zN~`qanm0GNdc2=k2L+dJ@CXY#A6J7Vqhlt|9WKLYf#cA6rcy`<4QM`jya5*(;*MFP zVeGbj=0L?^?)dN+$)1zzyS7)0?jRC($oM+l9JboF&#Vo(<0A=8i0Ybze z>MYvDw?T-wRob5pB$5E^!tY$*ZePJ0Mz9@%@`6B-wn8!)fdRV-NGRQ^ICjr3k`V*| z#F8jk^%jG~AQUwzM8|f72q;of&yp~mJsRJV05e~$-vpx!SCc^k(Ee25tG@BBOZ-qS=)9WzV3MlJaGPlQ!*ZN}GCk2Bcfn^TXw$W5+ftzx!8D{Q z91`!oL%QeylqguJ6!%-r@GH-5+bUhHkV@AN6C9)plGJm%iGSIyY&gpofPsxv7HLcp zL_+4UDo>WcvTYj7cy=)V-GIj{9gj}SEi{ysn+=NP_*Qb~F8dtoypylv@&Y2V-oAnz z0j*Z1^|^oobvD!#FBQoAW3^U@ng<%>Ep(hbV?gH;RX>8QTLPfShWe8oDNI|5al{r- z9|C;)!?()V=e3>7gB4L;gT^WqP_$A`Y}!i(9H2x<4jD|adf)KOY0WQG^wi}MacgW` zDj86MBU&ewPcs~+>CUnHuDTbUES1VW`q?2FZ^0Y1jViNE)dN<24L&WTo(#C!l5jO? zc$+gXz~J!+GJpeH%)R~(_mrj{bn9ADa!z8i#_@)n4f>y0YzPGcZ~!!e4CPqE{urY9 z&qj)$C!c&Fbsb)p!^0N`;~mb@aU)bLv)LNX#%xe<3nRs+l23BJ?0ThrUFaZio&Z6T zj~-vl^s)j*DLUp)iW43%n%*$@Y_{c#6klQ(fz{8FP(grOs&yqF>2g&u@}% zGsCD2hKtz!$00?~F>;Y+ixF4#L1UDVfN$`;NZh>*uXfd4@TD~{%)#;J5YON9>?YrVZTM1YZe(r=$hN;5K)S(%pATX~k57(qs5A4Ju; zCq}a?3k^|c37{KV`QSdzHBu1I1Rw{i%d5%!XMv)I18`b(#d`H0E0lh;bqc%)V-xdg z&Kx|78pF&Hj!qvxP*!;Jp{n;L^-n&udtFVF=^U_z`}HJ<6U*1(etLw2pC_hH+`Bz$ z==F5J;6*?vk#^?&IrM}yFtrE&LhW|jM{*6d{VuDAHAu4@k9IRmP+CNME7 zFadxqKJGhn#AA{c*y6JxT$V8UFShvHZf%?4i{LuZhx1F((>^`C@$NgV5nqR2DHwnH{nPXUWGH$1?H$7lp9WrkeH<-+<6-n- zx&$tIbnNEQNcff2qu~?xav0~>a+0HQ^Yarj;k$H(M?+Unfos;HAq5I?lfi|Qcm-jJ z(sMk7ox&yY`f0BejXN_RVwYSJagj(dyJNw+vvJ4bKKy8wOELQZlPy*W2ZtnX8rtt`to z6xdl`$VF9_-`9AqbLAW_5-idPhCzVlsp_wH+E!+_0VjKU-@{MHc0RA`>EG3-H7Khs zSkJcEw!QudiJ*D9Q8?bdJgXXJFX z0%zH_Uqk0M;$U~^aN0n=%(3$WCcMUDBy=#qvC#e5bu80lwNHd(!WWN+0tw4;0e!u7 zBFlfP8Q8TYVwsMDGJpy909bH3>%zd(K&0N1*+)SV>~-f*Xom50n+et|LJ&`rK1?V9 zfO3FWxcybjy}4zRpWG!9;=Ck@1;>&&;S(Zw&=54!fh6LfQLfu=TOgS+wNeGAu5udh zi;(1jAr=xX*Z9%!>+L44ji?KE5DHAxbs9w7ION$!d?Ki_eu}>K0^EICyBP~?o#b4W z4r~_sy?mIoV2yPRL)?1? zHPyFk-zz( zdZVw;nUmno(pDDPRC|q3v5wh*?|}#6;Q+BV_nb;7vH(d}UUmgvU*##3mbNQkCuIyC zghBji8IcPbklU4c5m9t}`%0OEca$ihCD=vt++-)*`4#YWpv!!GCRfCseKAhFf>CNB zU}=+YpzkNehIi%$j5z`W0HMVg5~%LH&G>O%tR*~<|N3-|ZPIn3)NaYX^xe)%Zug8k7dSKL zS=KG*)AdOXBYyVs|)w(xI0vg)4+3?MOKE(oug7O2Rcm`YZ({r_^CVnmqzM?uZ15xWa91y*f|Zp zEncjvcDWnm`Eu|>(_%gA!rkB#PM-()gNu(EUfm5j^YZi8)y2nb+&x;l)6j^_Qp2WW z^zzH0anq%LHBvi$nL4!ek7M+IzmfXY>S#O)?U3yj)rk!C%bPQnG)f((=4ih>_@|n+ z$IwzBDL@IIz(j2m6v4OzL@VtlV#V%pl4KyGN3?w+SVToClM*{^jdiTu;b>AF6O$E? zq9opzEJwHO5_hl`N@He788xDgR44f{h6uW}GC>P@q(brf*f#gv7eYNGt#0n9rmzx@ z#+@YwaS#T^zI>twMW9H;ElqNa+8xhrlYMk2!>EoZKxNBjHv(x|?ujqzYU}_von(38 z@}5Iq=PEEdD6{WGjJI=}r6IH zXUbCO@V-NXhjOB-zwt)5U0=4~Q9hJ6ojqw_aY&?ce1UOm*YrvCWs4c^gvG1~aENqx zka10a>s!wE@O__J`GM(AS6Y7`H#++A=Z0a+3O!9`nTVsXj1vFk@lr8N+H{Cv<@-C> z@Fnhx75;5nS9)z-;_~4!(#{y6no}VKAD#cs*2-ur`Sa7Rq-EUD)A;4E9V3CKJhtn* zZe!rR8Tgv@)>T_t-`by0+RODZmz}(GIf_EIpV}1e$=SCF4WFd%H^a4mnCTC@mvfpF zM6_En>~T3VVRHC@muUz_@F~-o}_57agYrns}Hod4& zFn7AUTy~Az)O(il+eE6e^|Z9Tewt;ZI)8`*pNY33hMhl#5FTgLI z2HEV?OCRMGw^3R#G$MAN*T^(Qdi}SM=sK=}Enb(=)*JV1J!LGOSjIzd^9PWZJfA5p zaQE#4|ZbYs*92&iu*d}09?yuOgEt&y_DT5)%Sl5Rt? z<%1OUSvfl|=r>apMN{0nx7wDc?pY?v>8A2%@+e>V1KkQf8L7VA^3rXoYZ7WOQu2=K zG-o%Jzob(~k?E?U%8p*?o*C)p%SorCl{OMn5f@Wzq%)$7Q_nS|CkB8k{P~PkKM)!- z`qt;B9!`x6S7v41>CRFDT<=8#TbNn5v97Fv zEM*{DjYz&Z=L68P8;s#9Ot=~+ON*S{T6A882LlLMYYRq*M4)G8cfp9`y)oP<^l~MD zPgJ9iQq+yv9egTo2OR*Y(2xuA$m&hWxM?o9F{{2ZLj6k6sDp!}69B~ghSShX9Q^Oo zpyp|$F&iZJ+i{|gW-fy2L?D=gfbj&?+ME|Dn(_c}f~k49TxVcW|By98Q6Kg<)8%O^ zh!(>k2(Ui`8ay(AFh(7LgG<29A|h~x0u$hKaZp-u3NqR<@!yC#&;YpJ06#SfzHv2$ z=s{d#0_2|c*UyJR`9~^7*jjJ95y6lOgfaaP5D<_7s*TCs6vM%xGLU2+^XEeQZfTm# z3tDf1BRH5$4yGy}6RnBG{IhX`rnF5^5DSz_$@O3HS!KutYwjSQ2G@Ad!@=Wt7Nk7{ zI0<+#hp?byRB6C>cG!(M(BDLO%r)if!=mE1a$ohJR2@8=hw|hiY9|r9xQIFj6qWD~ zErW6-t%z13WoYllNjS(rt;_{cm}nyaFsI@cC{|w{UTW)6xw#BhH){S$ z1iw?jd~#Nx4!Z=PnH2&Iz?x{sri1Zy<^Gf9!8d%mdWswl zRzSJa%^8siV5ta*jiUwtdJO30;?SD55?a7XK)|lpNA^WguwTV=3<6FS{K)|SaO@8{ z0z-`Avo?k0nt<)a}!$0_3j7M$+x7DfFcD3&57$wWt*(3>o0s9f^;HA zt}X&Q^T`0TATTG(Yl`6r6yQPkjcJaY#hhO2VD3Yi3TRriblCBY6ZI9LY4Itl+!(ig z@Xk_!!Z%Gofss8Dlzqn@UWYw@*Z$s=DSW=YdKH!Ofd!Xg!R8(B%h2vG6~k7GVavs^ zg(lcs(Ea7u`#>{HiG;}pDi*%U{}KV68nO9=T2ZrF@x!%}hie&tz+dlu-0TU*>kklR zA1IX^5Zw0He;@vKL&KljKf@maEBF5le*r8$D0V3D~0Vz$5rwlhA5vl znM?~9*+jU6971L1Z}Tjow_Z%aN?yuyy}9y(H#`m@TtdGdE$oqa<2*YqG4=7)qhp`f)p2yxqHjTG6bYKqJdZa*1=%5e z1I)ww8y80}I=`4d;*gB9-4aB;HG!0p!G9Pl^nMZH>!In9dc(&n;p4X}0a5y*dHHu$ zDSrEJXsQQWhltcI6o>u0PE?mO20iv%&A4L1 zxRK{?DtV(gYHG5InWnWl`~^+js=iq>RRbYhrf#!3`C32j)O`rr7SA23`9T}DDQ~~W z4ngl#-_syIUE7V{4C~bw1-qRxzs=bJt5p11e{4pFBX!94$4@s);YyoY7sHvKjT1L- z|7x0k^y61E?;nKAhm*gbERWy*{d9ft$M0tVMw`d}CoYIpzr%YjY%~q6=)mU;+Vj0@gjYBEO!dCZzFcRu>AzRC+rIG5yQ24jsTbz%n-3m( ze%TaSoOo!98j~y8RsWm zfAZ!%>Ex3)J*cwvrO{os*Oo2(wtZRnmMP|^+h1~eW90Q>-LKUjtj}V(7T?*-i0OvM z_rjlKD;%D+;3I)}UYk^CyxC4!ixysoUg*B5nsn)U2vdCQ&%(fooqJ8bG*AV1zdx~a z!}x3I95~Or_%-hCI!~D(fRH0Y2$zo**Gs@W(!iM_R$ zgESojfTHff-j+=MP4kUWEFf)-6Q$CTgn1@vd#h|Q0cAYYFCK5EXz>`?v=|d6N6=v7 z4(u<_d0u8yF$@>G#sHA<$(PhlcG+A;W&+j6{MRS^^>-8La1I$aUY4}?1{`H#Pt3cY zp=nXtsVBSFim)wGLye&5|%>;ZHCRezYEH^h;Nrs3mzt%LbIGCp5M39Id~ z_2;%N78%R9k{U|^FqR?HKtLIkQh`1{ze8svKgcN++(C@oK8VVAmdmHof{@0rtxX(EWQKa9nL}{cY*ELGCAh z?}~Eb>1T3V>;H^O6cr^4)2PY2KhxiwThwE&m{06R48BQv)G8zCi#5$vkM8$sS5e!H z3&y@>G}PVH{L^M_e8@Cxo(jy8v1IJXf5ZiYJfINa|5scvI47dwAB2n1?9~4?KdMJP z#K7mzbOqN>fS1JD6%g~C#&C8{Ve`<9?Ii#jtua+{`563XDcgkdR3I@!NsM4@xqHJB zE^Kclu59!XWOAJ(=93FL0J1;}4-tNLT`_Rk3QFsmuU%upL!v3&FA1qYdn-h3t~6hs z!6D3ti?_j6q~CEL&9=M%LW7V+w-gMA^ZF8;wV%D57V4 zWIOMD334A5|4i?)fGg7FIEp}!bQ1g?1Fe2X#R`AD6cgr3m$27U_(ef0KPr214o`*? z8EhDlN;kCkAeu(nd)z)md*^~r`%Y&IwhVM9%pv)3X()t z1hg9A1QtcjS)j!aVcvywC%RP4Rwy*sb?&Tg#l@_*t$s3a-@=5DqR|yPs9iJ}Dph7Y zJqEy>-lYdq1I#TE<|pbRxLgd2j$fgGGXxtxNdU#zysHOtx9p;#_5x^#`e8zoy;rs$ zCUs5}YtEw@taBU|i6G>jzr#7VNIF~u0F@m{0d&zL3_6vA*s+ZA8qwYu2jx}H5s~^; z{rbza#C580Dib$JIt+cZx05lRN$5}>%7=qELPI$)5LqZRQZf0DTB-=vO3TRfwUORI z4VQWfc9|pq&=B#AC@K$qgqCrkAjN=#n8-uZ_^hq?=um=v>hpg52174(0c_$4<&c2w zOl&-)^RZ-ns2L}XQ9CA3w-YhZTv_?@P<^b`p-XzT$6amo1zkH((S)pcGA4kUq!xxc zkHSQgF%d+JhKTx_WHwwx|8kM8^D);YvW@QmT%v#M;4Fxb=8KSOqC6--i zgnj0LqQ7kQEba!xbIl z(en|U>SClYRj05s+6PHS9rOI2FcA?&5(MNqdN)+r1mV=5-LP-qEjH{C`_ zFcmgjhyxHP7#Pz*T~E(KGcA-8r9MK)3Ajk3qnsKqc>tKSD`=<8cz1dz!5F^B>-8z+yfxXGrv5ng_DWq@zOUm}FkYuQQ>qmvJzPFrSFhBA+f5zj*xgjbB>}v@azcp!oIqMLh`_PsZ7X4f!!%T759W4QX&@mh z-6SV(IaG@UJ*BUrLkja?&Sfi9n**jwB&(v9apKc zX2|MInoN~p-gR1WMR;sgba7Q|Q&q=|T>NSkU8Xw8v^wQbby{pS6c@~Dsy@#jtj<}j zX2{&SXnO0?p<9Kqw~C5y6~{__xfB*%Ve}~9Ao?^d4{9XXZ&q;Zp!YG_wSL{Qru?M+ zv^+!&gdVy!myoG!d~;B*Oc1PTszDk-p~0Fw<=Y8u`gK}08p&jA-JMn$lQzfGCdW)Q zkKOTpXfRC&>*oY_e9L?P!nl9+PDGn-8v^l=YhJs0$8rEa{o)>vsP|YL3K5*u9?)?X%(Z2=FH-|KJ>GN<{G4MjI?oiI2NuD<44=Cx}!WTykKMvs*z8#pfkn zJ{^`8DcmxTgfn2@sJ5!f;9dzx1%bgxc6@H0C}e&AlmjU-5)8;|eAG&O&-ni9VUP+$ zfiBG!DF~1McMMD0(>+f-m1E*w&a~B1xFu&n=NO zK$4EJAfV!?FgOKo($GkF>^w>VBv=@b&o~rt(;{FzQ)mGZ4ZyLaV*z#GoM6}@N$=EW z3>*?$Xp&5r44L`tylZrc5qzCW?U<*fxZCF|Lu*_>l#Nc6@(lBUy5V4OroB!i__O~O zjDW@%kzq8T>w{6KIM7Cg$Xaw)0F~7v`Y%nzjgCV}GQ_t5or3!C;npj+55VH_e@FtV z-qCx>D0c&CcP^Ug{&H&P8XnUS&srbK=rnE zI3%cWkFTZaK16kVVYG!_O18PQDVc9*?P=7d*8F4gtVLb4XNa z#Hn@jX};&YX?sx}_`~c+%U~wuxgZ6$MgeUigsV&8NY;zQACGhvULeSwDeN9T`Q`OH z;54=?mD;>c0iA^*ou{|JyVrO9#j%ziq*3?DA^iQeoO1whW>3^l09*%pB`C0(buhgD z6-)RvLjCojccyyBK#NQOPXp|TgN6bry|VWTZ??kRVkpuT}$?)(wQnj!4Z-w&O{ zASr^?&*;T(r9Bh|G-cmz`2kb8TdQ&St=jgtTS{Pbq`*sOnszdzJHFM|`K#aXY`^}K zW2e~xXuH~rj{?bC-xZ?;dMasYoFJ&m`|gK;l0zYF9E{5o8f81}zp5xhz-}nj>;7+5 zlpWr3=z-^~e*;}=)rQrO9jyIqaSA>)l(Hh!jh=rQoj0LN3T1a%-nKc(C}>dTmq$`T zxt*ek|7mnK@Gp~QzB;eCZ-}@Db~?A(Ij$O8ccuRBXUORMVvm<9y;RZYTIFQkyDr&% z*Tj2sk;4Kt(CI6KSa&K!A@@Imfbw~Dl_2QH3jXdVCI zsjBaq@{qr0@6(o;_xNX(jbdFnSB+1_wtRZ7ireZ?7%^G%t>;z2cJHf@ih}H{FL3sW zpZR*y)!ny9Bz4G2Xd6wX6)BGLuO3cwzcK79!+DaJW_{RCq$B(S_U5&8_v((}Y*Od4 zh(!52UB&HnJXk@pp+Thbw)za+{eilYfn#|pX!eU8&(@!-CTSkXc2*7Pt^is8}ME?-lr zByeqSwSoNA^M*BtvhhC?9rNqGM$lp|`ok%*g`Bs3npq^*k@B3vpc?Nx9>aT7FFkl* zr&Vvyx9U1;`E+V>=Y{hcUvIT67JImWF@4=TOpYjKUbxDg=-E-bnz60eRrvdlx_683 zl=e_7b-HDp8)~z6+?e(ql`kQzp~OOY!#f~ci0$)k|~&e@KQE{i^XhR9G9Vs z9d=mz#YV=BL6_7Fr)+gEcG+)tcC_cpaUnTIrLNZdV7*aQ)z&a?V^=N7Zn$ zj%ug2YpJrGvd(BWJm_%kACPm!S< z9d;s&M&Ebh)S-9nfwvYuQq#9D4)|R@wfHHZ>h9uT@Z+D0pJ`p&mxdxfo?7}6{Ze}G z*Z9+X>|S+?`R&n(iHKdx!x<+g+IAqeTx)O-GY{$8`C0f5vibCp){d7KcSfM3ckDfx zQjrpQtzPVA)xFiJJC8S2l&&3X({&$1)_yj8zqj_QW$D-2Z#HJuF zuhH-IIgZ`VKlATALpN2F`+pXP&iwwf#7*D1u{?G;bYo?r>i)*+^yA+fYrL+Vd`LwJ zeKxo{cAvko{*Ru7B?}|rU_7_t9CrH4?!`P)q$%m#G{?>a&dUO-+vLINzyHJ*SYkFt zlld8~+T;Kb;m@Hz>F za+XLnN}_-*GbwPrO@6H#%Gy@JlQM|FhO|9l&Cq6}UK!}3BuaadllCErNv7>~)9*A0 zq69w~VVg2SbCE^#dIhNLl_(Iw&H<>Dbo08avYYA1;2GNLT)L3dK+ZY8WRw;$QG25` z=j_1f#iI5~1-;B>>3Hi%g1epBy5$SE;s=-btWgbfR@%8`L<;M?swP63jVsnVry!0s zi|ToKWbv*1cgAzlMj75m=Je$$jV_~hU#BB3<#;zQn9xm!S3!sJQEyvr8s6H1wpX!= z%J#B1Hd6N48|Lnz)xtfK7B7w=42<&PG|wFBx|kqa7&; zv;DGPm(#2+H||SL7?qP_R^3-i+(STfliOIWSbGvKp?$W3`05)*#c{iH&8R{;WPwLh z=wa*1@=FaWW*e>9$~UuwH_zef#dm+{T}1)ftaM~4S7Cuvw%flL3&;&Cn7-%k zyWIgMKyYAnX|}v6q+#)_x4Pa5QuYLZs@S@%i`7%^Um|nk)+^*tnEXse zm-*g9cti>v4X|K__p)-&b%))3+SFyfu_-6f(Fm5ZeT*VqmQ#j=69AAFox861!E-v` z$L^;hA7zCBvAzsnodagV!707~RP8J?0Kfr$%E*oM^*gr)2f+k)IxLPt_D4}ZJive4 z;kw)^8&8BtUKLw|-fzEOW7_WuFp=TamO|balcplhpiS%%k`3&1amf09srPQgmiJwN zMxlZ)fsAw{p$rB*aUl&mrAi^@atf3rTeds=@$>DPL$l>Y9P)7iy<+q+nDeH|{W%4n zK-OtOM!mytF?I}v6to~(l2{P~rAAE@aHq6+`@q0HTb*-@-MmtwZ)=SVL16|nTJF=_xhUEj9LtwBoP0?%a%Y#>KLtm-P&9xpg93x$;@w(OkZFptHy2N zW4EfsioF~9hv4n?;g@)T4}(r-B$AkD3~)v44Y=?H3>iGn?cJFa29!HHXuU~R7|;MV zGuB|;G3E-P6){Kz?8a8;Yd_|&#liu27=tr4pimM>N5WdH6l^!rD}PR7Z!4Mf^Lctz zW`7Z-`G|LEw)4O>dJ_E7F@-6wX{2}{O4Eno93@eua};#{rOD?Tez5gP{Ge82)AWK>dkVe*~Sbbw`ELy-^z=_5D528 z%ec{-m4A%R;FAfveXDOvHjU0traa$l7W^!*av`JhzO}*68;cEZp8PuV4|M5&7W~9N zi;J3mWrV%H0DC_nmGb6b#L>9BzmIebx(dRJ{P?WKbA6zEE9|5+8P)hKbFpd!g~~|V zjSQn3M<I}qMe|T6z=PN*8@+gcrl>ocj^+rxXX0mR9vZ|Xmt*lY6tpV`DH9F!69wal z)DxPYn~C5o8@x{e1lY$>01Qn-1kn}eXVUSafNDc5M5z74 zP6_A0&?MXfpNU`RfE!%=doHGv;?WOH+iZ9y9fTI!+j$UO6lqODdh$>(Ktv1{hxT{i zQ-wuo08~TslS=->f&L7R#lrP-@#rX5bq@@jAi0}`FybHrxhNC*`AFA{o1Pwf^uY}} zV#dySokc!XaNq}5Faf~Z-|!@4KrUZc6a(!*Lzt1FH;9BfOZG9*E-c9$u~?7e;NKW} zy9&WD4RqB9$H=%QqVO*+=vjahV!>j$m;f%yh=#BgNg{I4!+o(Ua~4a|bSlbb=Z6C; zJdjHeXky_#Q*pvXSSl0qrWK9*gf<|+6`?FB6X`*c2?~#0rQ}NSHR>1NFQ{vtn-zPa)Y!4kdAp?E<8xX zT_xngTTwx5>>bLLXgZogD!9>gA}%v;l|{G~>Gp*RNN~|q3d)v-xkVE?#k_J$TK*JS z;35H|Qb_a>HNB2Gb{|>1qH$Jh{-{}CF@aBn-9M_j_bt}7M_JlU)d?6pgUM89+m;mO3`}HCNc#5%&f_JF_r180c2lJ0()b5P8@g z1vnhz`cG;xo?QdqFXqTW2CxM(O|a1%;m>qT7V*+$4r;$+(tSJl4x-R~F7SnFnNwK} zyj4P3invg)odCm=jCn`KMbJ=9WLzf&+t^rj>oHu5{y+`Nuak;$-0w$I^i;jXh81_T z^I4b=gS8TF*mjCg92426n_F@Dfif4aM23A}d%?9HzFsEe!Z1`;t(AbB54F^bSXYTb zz__+sZ@>v`q0vT+2eU-Hgb*o`yUz*ZO;!Lu=nbsID%1&!0)VbYnv|s&(p3yN`rtkW z{8}g&Oo2-ni^XP%eALyNs)=3V20%pVPpfN;oGPLX#Hl&w}~?qKgOdW zomFfd-npjNJh^XYr{^Jj!?Df{4MxnD-1B^P?I0$`4-O@k_qjj&dE27ok^?dryq1a6 zFoR1V%TYt@(uij<4o)oh1j%~n|5iYOfW}EViO0LbrokyPMald*(gXjAig*Zse{7y> zn?L{g*}jW`WsutRz1s}U1$2Yk7$gBx?=~pROqPr517JUF0NeO>yYqXIG{C;JeX6b< z!vao{_TKw=1WrYm(-Eeu4pT;lDGljHM0uNc`gwPH_aaD;g@_!7<=82H!*vjF7)6@6 z92rWEJi3e{_Bs)ag`L#)t+VkRDbPVCOg8QAti)6K;=sxHIH9pC9c(vxB${%=UHv#h zi)UFiXu-K0C%3XmG7pDbD$fG5Mk+1=r`RIm$d*v*AAXmg@5OOODwYS zfo=rPXD82cotvL#lMPSodVB&hD`n;rq1^*af`eaSgv=4U2@TlS&IlM2RssA~+Z%W4 zMt3F&IKu!Gd5*+ya7Yge;lPE7fEw^ua|>u933SKDy<7($kj@|MK==|mf$bxu+a%mh9rtQ(Ut-}pP$m%h`Zl?X&pzR0FQg9r)9lx;&DafNg zN8xlIxw78c&mmD%IG<1POYewVChb4XI0&-Q+D{(4BOs(7S`Yy61e|2rldhIH?Rl^t zl9@#0x4%{LDM#xQfyh06_3nfV!EyA)Cy@HZic}KRxPFj}7NNkl9(;q=d0V$+cUT3B zA{@rU(1cnaJ4N6mu?Rc-;UQ*EqQKh`NWlUys?fLk6o8^^g#*G+$^%|&ffPa4emsKV zvCdtxc-ae%t{0+7Fkd#pj*8e6xyS%m;$Bo};iJ-3e+H_j^RiPLD0O*FHxSyo0uE6I ztFGcC4L^H)yVA$~c;};C3+)sCw#AD1>o5i&L1qx5g$KKgS1`$oP`y4E>naQzxhqAOHo%ER67;w*Q(5_yl z0YT-oOeLDre=!otZw(pNgcM z)cQH3U}IARvfsD4Xa^;?Ac2-X(vExJVH9sLONII#W3_A`3IG8)4W; zLNRLPM&t#PF-AV#(0H!TYDCu(-S_QUU^SbDucG0*t)j#GykmiZQ z;xoyhW1SVw_`EpGN8FM0z{U7BlG_GaOm}{`v1ufdmbm8q@QuafvM5>fPQs*`9A zhxt5{J`r5xZlT}WxqY4cu#5PsK~J~z7RypAy(4IP_NDOFNby_5CS_+ZzFQeofDuP? zO!6{h0EtV_gCl$`f+hEe#l2H{wbh3c_GXugq>{__GX(efKJVMAhXG^ZaZ$0o4SA_j z5tn*T7kHqlCqB}u-p~5q!=DwG3Zb{|XWZ}P|2*^2?RaaI*wRc)rM1<@UE_leA0K`H zoNc#bW$cn?$jY~(6ZcleOV9jTfxvb*Ud(o@)8N>nMif}R>4EOB7a=I{f_Rp_OE2k)GmyM;lp7+J7 zq-w2~2w-Ouf%RiV()qGJ8x6*0b*xcu8J^D{Z#!3qNM(za?JDeUSJSOcAo0-iR@f@7 zLo->1kPwd!Z%btdX2iUOSX0Beu=vsQ0nVdap6KKRPtc{lPjni!TXvZa_MJa1%r;^N zR1yY96*gyOQOj;CnTw2M?-Ziwl?+Sy*}N2Cwo=XIj8ylFQHsG`7HN6u*3u*SOyT1i zs9^`!;@L}S+))Ol8jK8nkY81U6SZ&^vC>MoG7+d~n5j5C9-nT^O2K3MFez`g`_D&>z~1 z8N+uTv3wKzHeafZo2otC!+(>ocv?~{T0LvAHa98$d74k1k|yM^3Z>3udGwY`AfU;f z3gK?IidwvG&BD}IN>(s)nf{l;E6jB8tI4oB5ppFw+8eF zl92#AkoEbC=)We&7!_jTs4bMxMkaW37KLQyTF&C*=tiZr&EC^SlHEo&YXX9EBv zWg&@#`KwUksPZl0ZG=3GZ3{K8reln$k`EcEojd*oX@FICg|*dyan1+%yBWk=1xsPM zF+7Cqx%V_BUTd!WZt~rL1A4o?K8*v>+*cnHZ38}%dWMECYFQZdu+U55_aqGYPSZAKB?fQLC_!#`%Bg1B+ zV_-r69U7M#+Iwy#1??;)$uHXJWX)s-Uh~B%SR{8@>~>*5U^@lA-AYemOiy;`c-oWo z!uKzbB zus@?6S`5|lBPk}rH6kwi0(8&@vfqpTOjLEQ-TK6l!H{63?oP4Va373cPeVIVO zQDR9(!n~%dAVr*v!H<$L+6?4?PW64 zjD@+_^`fp_%dId1H&L}$FUFr{j33r=A_`@e z=@QQNM?-_4H(NKUA`t}*`CR-EefuvWxI{ohi(%Mvj3yBl4qcjQ;#qcnmIqR_GgL?# z$v>(<#Rj25u8Mjc96^NJ9;e$T}H;XwkHC(R9nI;o;L z2v06bLpu6y*ta$pP)POg#@o^CW@e!yw2S}*bOSC zs0HX6tZ={|fKVPCf0_uK;9;X^h@C7%2peU@fqC~KDcqc>$9anrhpPE>^ifLgwP>sQ zD)8=maFQYPo`uA6u?bAfNg_g@im?aaatzp3?qOcv8I2URm2U7c9jRvwZVHA=dht$!Ah*DZ<7$EE5q9KcFjFc-lXIiIM|n3sn=K4w)o`h)^v@u$CprB&Ec7 z#+?(#5$FggflvK(rG7I1n>~O%AaIDe)0>F$$>$Z9vB22nMDx_n8iOL z0Ja>Y!~;|<j}VXF_ni7B}*|^c~o};e}Hrap+N*rGr`raJc(E|f`q)q!LLCk zJer`aj6ehreU&Tx8W4O>#;?%urCh@^-IXD>ZtW9b4K>x9{TBid4p^q%^Q*8YVtU`= zYv^cVIM_$PkMjw*B?6vFN8g~}*BFAo!p!2kV)Z4H_CzNh-w$)5fV(3>;R$bV-}1*y zENG8k=L+X>@xOuXN1L|67=ok+M#<^eL5;ln?$jUxT%86!tH!TWEB4W)J;*3a0&tuz zNGr!eo9s9`sSa+>M(E> zohTl!bRp|ZX8nYj#*EMD7cuwhlg`|V4G|JKy7nmC>~X~5$5C;Qg)O0m4#}|W#|dkX z>9T6&L;|q?aiCKymBUDEZaDwBA!n_DA=`M-tnt#}#=^M9qLTkt0%OWHm76tH{v&}^ zmo(KhH{JQ%bZ@PR^`8>ho&$K)uzy2#Oo*ZIIlzGtfz9S%*oRy4Qld{SI;ImMdd-|( zes1A7IbHXQUXFBoT8AAdc{14iWa#sgFU`*Ge7oob8^KXS%y`_>iIS&N&Cm}ziGDiW zNEl8E`=K8;-;B=pi*}L%5F~+0f*>HrzD^ZkJ)RBTv9 zFHDXI5Q&(xI{(5?de{_pFuv!(i0RP`xCG-RNP&q`V9miW??mZjD09idhaV;QvO4&* z&KDDiA2*In){9QqA>cG*R8R@rwfn*upJII>DI%l?qg}X22$PCWL{Zo%SuC)F5%<)N zFxVUYSp!7XqhSP$LXfXyRCb`bP-;ismEf4~1RyN!jVlwaTF6mdJO)|r*3J-Sv}2Me zz;ZCsfP^%mAa+p@kZ%`Gz&525dg5bF@z6v{@Z90&a2;G=AwdKebJh^}>5Vz`OJ4{nlqO0TRF)NuY}a zIKINUJ_*#Qdj=!D%{&9RwVyaN)AG z8ws;a51}1}%ywu7la^BDP_#>kQy0e3|NK1@H$cM4+I{{&|NMdU`Qek#e1Ac;PlKz? z4vQs2Jr|zc+ZA1P7tbJ~e2HJ)?fUZJuP*~I{BK|v6u>|7KU5=QNHt1yuO|JQwmK71IXfL*QJv_f zn%$%2VgDcTvrR&zw1~fWqG!m^vJxY^I79Tze>RA3vxUkJ*s}WJZ|B**ZFVwxn&HTd zE%gw41gb;Wr7=?_Zx%aWIpcdQ9W-_lH}@(})9(G3YSeJ_y&CLSyMWEag#xLacbFoU zFq={>N=>o$KMmr0Ya3cezTwKPvwVg!^pfG}lA)z^n4YBI#Abu|qX~llW!s6^Mh8)i zd-B~*RyNVKDB)`FXpT+olTFpADf7?VnG5f?nkB;f_~fI?R;lWFUcPN=g3W77y#B>8 zQ6NY6%=)q`!ozkiT_e1XWux6^qjz32L_ftXUf6Jg=(1T}ClOE6+h=-vopb=ujuds) zdB~pGBes3}GB;D>W^|qdP1xOOdp#~?K&=pasZ%zPS_Ug z#Q=G#V0$h(T;;{&t?H17J(ldssi_c4F8|RK`RI|ksk@Dn%n~V3HTB1RwpRNdk5NyX(||vsfa_(g)}2hRc*`$r>~AEJ0GH_dRgO{rxAC*tZk5ZM z@w2KsvoEwCL#h#}OM9+Y|09$)GyZ;O?zQ>S^xPXVX8SzHM(WgjpS}9s`M1tSKj-@? zn|U*L&r=KUy-wU+_~3o!XC$yTJ-0C6mt47T!1wZB!8&cmf{zA*Mr+`kxQ{pFz^=1e z*Wh`4GDrXDXxrnj&sKke=6}XqjPL2hKU^L)yV}-g1gS=iqcAGIG3zJoQbtd+ha*)&dt*h9vt9MkVG;rw*Pr1^gtr&@SvLmSN9Ki5z9Dlzo`(>PUj zImA4EmBbnnZsDSy)g}oz!|AY=y)eFF63I`~$?Jui z$rJ%0$s0*IWCgX=X|$aiU?&rW%YaXIR+{Uhaz6v?%s1m_N92G6Km%(E0aR8(I8H3n$MAt}peMIf|aBh?|fPx5-`pB5) z;t9t94X(8S66z9Y5ta8H_1(Tb#>qR@HNSMa%R-cpq>d$ud}DRSLY?1%r3f)7IVTOl zVh8{gPZb~99bf{pci(T+_^y&WHO$WyBTzw58X`v$IWXyY08WA$AUH@;gD;e#>r(oy z^XA;Ux7U{1U3Rw?T{oJA=qQ`iOnQ=dQC+3#DVR(R8?_l`%Yh<-v&t@q{om=yde{x{ zW;#ufM7U;AlFU2mr80bh5XIgaPay%=^P>vlU+i3N#q2LVB6dFDbJzbO?#;tu{`8e%J4J{Oes?w_%)T&T=sziwty2+V_S$RV4 z5)${M4-M`P!4wY7PWw%ACxyh?B@Ajcv!TV8^p3lG6lm6;du%1szn^^l!(AOR{J#&4=XMOuG2UjcM)b=E%*NImFcR?<^PXk^!LdKM3srjyY zvqcsEqOkO#ldd{wzT$Lt)UhktB=iUwbS{pYF78fS&UmLh$;e`ls*Xo<7CZH^M)@`{p{XIgS8rRpV8VuX&UbM%w9Ny8m&ypQ5u>71$ zGD_U3^T!~5uF>lMw?X`WL5DE#G9T-ybYD;L;2L*{_tL`oH8x}Wh_J(Mf;3q@xOXk2 z2D_!qI6)R_9(JjMK(L!d(@?pcQ>pN4s!033I-ui@`k|28CYaUQo=kPAchi24+lQ0k zdK{iXqW#XIJRMEXk}KB@+5A(cjfUB1u^Su$Q693Mlg2R0$r7J1DLi0t>d`OIoq-3)Y1Squ%=)CzM>*UrbTv}sj z^DXLpujO(@!MLlfR8AE+4-Q+H==T#qhJvF*2J?=|BgRS93m&g~9hVv8Z%pz(f|i(8 z^0xJRNBBOWO_8LLgl){^t|DBrA$dvF}hu)i*REyTRa8+Pn24AZ>Qm@gNakVp?LUf zhqRLfh+I6d^e*p0c7k17?(4~{BSiY404^5OXChP|^?M~kMkNG^^8fwPcE#{0CHo)hPU z)dYW841QaD+7I&Q6RT$!fzmx&#tbuHecll`x`2R{040Wx1V(|F(d@Mq5>9`*Cx4O; zMFwGOYyOv-OcXEEg)KS;cLz>eTAXt6$vHmMix$}ilz1pp#!N<=}*DazPDT%s`PKQ4X7gyeih%Cxh4)c{f{XD%SS^9WmhJ5|oa@af#jwB&-b< zL7@t-A4$MT!W}=101t;T`k%n&rziprb8Ga7=puGC3v3qpxWeL#Y#VmrdUfoO} zXUp+Tfx+qwZztRVn!?$Qy6D=B$*Jq&gB}0{DnZX3w!)81jk=kR~k+(#$O-4aBbf7fP8IhPh@+ydH0ZcIt_oP zu=a?H#nNeuCv5ydqdGRNF4Mm*JH9SAw=PdeHJ|^eGs(1D1(P@Z>x;|~CGqvA+v`im z>Lu9-d4Av--^g?CiEtLJPC>#0Gc^G`>q6G|U;JYbmj`QEk>}J%B(5m_#Og^ZNpY4e z$wd}2BhP&!k|?6fa^MFKUUibA0Rlxuj8e4S(d6F(;>m83&$G*4xTIJ#;$CROnZgEF z4U;9>c3leixPbV%Z##kuw*^ErIji}h(78%dckZPR7vZnO4MHlsh(aBNvr}Huk?)Qc zj7!=RS%-_Ry!US?7`qZ74T6fu&4+MsI?&B2Hb1mO96qFQk=rE5)Z!~YFYf<-xZz`a z^!HdX1QT`U{v`t$@~n_nu)>5zh*E%pZ04M16k0;&jgol{&8)1V#pultQUsJ{ej~Hl z9zKV|49J1TINt8bCO;N0V;+b&kQ4{rfJPk8)7<|ca#+%!0E?FFqZV2r(dFc zc__GC<_TevT*2m3=c8R4-}1mF(Z*%&76cuKq`{tx%z!2j_O?n|Hk<_jK)2wRs+?##;vFDBV<^ZLZt1p-?UI)+)ozET*<`by=PF zLK_s4Ph4tpW=euv18v;xHxSGln>wP=@J9-(Q#WcGX)jP^Wh^qw&dY&im)3x=*4cQd zyQ$>>9|hM(2n}2vDi#hW@IQ@^Hn$MRZV1hwA`>xq;}i>LK21nX22xLu;{-r6?*!(= z?K|6BKgM?-zY+3pfKZ~})mo`Q+jQmYan~vW>I&K|gZR72d5P6+)|tF0 ze`Pu>GB)tm0dI)w!;Rv$`t>=&nN}dI9JpqkZ_;>6y_e{gttUZ7YC6kP_1rAA(*N#2|ZcJ157=7-YXOhHS z8{5sqwp`dtHFDUH?qC4_;a=NB=tX%riliYm>HW3g{kl#4)#d%FgZ+)+{mqH}nv6?q zPV*0$dPy3h^VPuZ&Vk#n2DmE&cV7*xYC?E5;nQi22udA--oRTKe5&~HnZ?85fQOg6 zBik$_hYKTVqp=k(W3yEa$-JNkWyy^7G-w zw|7{Nm&M%Ln%>n0ko0yAwteLHu+?4vCZ!(tIU4Y%<1+b}qpFuG-QN1C<&(#yoo9b2 zeSXn&*;dDP^`DMQ^kNriWbPzacA)7#;Rm;UbdbXQ z&MFf>>my#2Y~xgGFMh?ef}bJ#XXd4NcnXH)WNN?9);JyV9!@Lj-skFHhhaI?9_{gC zhQlG_$4y{)Bb-)DjTg|cIumfm1)h01Y1U7ibTj${`z#!FJ`{QT?*DMgFS!20>43wZ zJ`^)Dbv~8|KUI;>gj~pZ3Qt7pKSp;;Z8%0daQjTT2s#PkTBDxtpFFS+9$eZy5x}{{ z1LE>#^9Z$eMX@&~x}U0xyo&p5i+$m=Lh$26pK2CIqpz;&VCV?-oczgpXLjq@bWKI6 z(7)Jv9?c3>%bAFhAi*=Q-iytT94=i>l0`bp0x1n{GXn4%90nZq00^V0IW@%)^DbWX zqR@}ghU_=Ew>^p3kZ(NdCdq1_A!vNu-mgsXdiv$+Hz%0#8u&1{zL1TRutJ{9!8@A44`ydPmc^edN92*m!-2(zU2~4 zt7>Jl0eMm(YMW$q2iF)eQuWw!POu>h7~Vs0wS|Mx1!sQ7SRg?+yYsOXqP2dr`GyyX zE!!l2ic%lX8~)mC1gEE22qa@}vxV#DAp;{(mf|7v8SmGc!-nG>*S4+93*Y@fzDG03 z)`FD{4?tiHoI83)CqB0HD@4Nd5s2D<4&nAt^Ns&s?!Ir63+5hME;24>fg`efq%~^Q z;A0Z1I?4eJnBaxwmR-Ld8=OsO^fA9TEjDj;42z^Gk^>-MG`Jzs-RO-yJw<+7=aaht zQ@&yOY5C_b9llAQ^&d?wKAR)M3SR2HR&=X1{Gq1E1i+Aq$PhokV_RCgd_HG<@9h9# zN>|3@{A+b(A-xN{=cR#afYHGNyfXYAbE_cu(9;yu*dTdvJnHx79pLhM8teGueJeD+ zp)3VJgDgsD_HMD8O&HBV8WK>^=LIPRP<&*%hQ{z);qBRirY}JeD_lo0G?k^1*d^i( zTx9BK4xdE;BAJgPFLjY$&wkCK9U};?`xvNIvh!vHa2P=c>WMaMy_t8V&hpU~egLtm zY}50DFDyZ(f$lrKAn}b0ZAE9l5*SWwu`0HiLTflPU?xx{V!pSwh`G-pT$23xNr9;t zP2@m{t%wV~OR9*2+YE8_mMaW9&g?&V3SA9hK5bC`28Es5ld50~z|w=wz?EhLD<2Aa zzeGiELj~!dIOx1#Iw-W@63*IVAyXOf#Xe;B7zZ1$6sE2yrgkfp?YwC&zIIMKsCwkZ z`u&<~hsWJe>@+k)&p-OTN_k}J0(Ic3u)x=!czQD2h4SLlhLAT^CGmhZ?ORKVdp0hM zioI*Kr1hv{^-uv~qss=k!@hQXe_<4rCbqb$H6&&Zjn&3E?D%ANEVxL!c*fBRT}e9B zl%_NZ$pb84NweJ&y8VU$mQB3)r1ioy?~PD<>1jm~Jg?a8XXLb-;H8+hTNsPcaZ=4o zqYlcW=)qeKo%FaO&Z^I2-BXh>$ni`Mlqzuw^H-f6_DsA>3HAA`@sW1ffqJOHRAfR9 z&y?7QpaGm;w;I@9bUVofIz)9=)-)eAlT`!7d-XjJU@jJE1YYJoZSdGRoCRX$H8QF8 zb?fzDQmV|F*RlUMNU2DLMK0b$z(k#b5;`0190;V^tfXu_W-}5hkvVGp=mhcDlHHvG z(Wq>Zlg-J;0AiF6TS@bL(z9u>U4ympTSt!k%f+6J7tpI2stDr5xQdw*R~<>qS(bU% z=j3rvT=QP~8Vw54`Zv7VgEibvy|-kg24t=eepnlMlMpbHhBRSV9TJS=2_tq=%5yt) z+T(<|-qp5n{Dv{s0H_5g|8wi;NHfDO8?t|7IhL@MgeX6o@$7_uDNxp8rzd^lY0P91h5VbUh`Lz;?~P@7x&fWkh? zyfJzvKTxKUlkUU{QsM{@N?%oxq(OD~c((7HsA|rWdKg=!-D@4ZnBk_#+*>*dnrH8X>v5DwQPr*ND_u}W3!QsTD^6e|} zOEV`(dlwOkoqj*hcW<9Mv#El3Pg})6|49yM(PY1VMB&>npYr$MgQQVRvsGLcrf$IE zt51oAF}O`8guLp$IrPh_O?I)U<~BOfFFINA(E(k@3Xu?gy6~ehmt1cdT`oI}BmZ?` z{Q=$EB6R%sfp;^(y2uZreol7sFyKpNVcjoT-=q6$<2|9U*FMSVnKswvMPG7=(zM{b zZ{(pD4xrCrCMz~~tHid$ET&AH58ZA;K-Qxmr{S&upE0#HMR%SYx)pixdbr|Zu$R4q z4;S6aL?PM4C5~mn!Bm|-!=KEQuaj88KGxuHif1uQzCnva2)`lX5QUmnlp0{jqHuA4 z4Tm$e($+5~ouD9;;b$ugHtAvFGRaaQnzkje2LL9`ap!AX)VoRYFB(!A!d+z$V1AI0 zrgx$>HS|cv!3!CmeHAX>2##Qi!uiET3a&}WAQ8JkG!uq%I0qZ0;{(&*{y2>4%3x;N z%pMj^V51pS(gH)Q0m4i3$v?PusHs#LWL&A=PH&AoZ*-V74-H@O^V)E^G=ezSIjkfl zy>Dkg8^(u+KEe2Ntw-?iDYTu4^TbN*zPZ^rXhNlbUfSwc~dA(GxY7PUyh$ zM!CZEriI(ZWenpAO@wC(&2AR{kvA?C(*Bk=+HWgzj4N_FQ{-~9$ZfR9W2uP#x3JNB z+bQ3;Q+{Vo`QJPhFnVg|(kX`A=|DL>bshYkGrP`JN>qF8tZVjz2OE)c#Z1%UgWHN@ z;))NA>c0N~D<{Mr&5~@LlI%Eyxy54muxGiRTfksWrI{Mm~fG37f?a_z9onOOP) zz4`!cA4=6Ol&5YS{?{ez_u060qRDQbR~TXR$A(fgoL|% z7)Wcny!8}$iLuV&Cx}@zd1Bo9d~`>^SXt7y4RQ%64BJfol=ropEgqp{T3+*_S>?}M za$J8ITD<88oxBbLM_JWELF6)nV6K3)D!Wb^aDepc9m47-`@OyzHo;*Bl8XCPwEhAF zmQl4@wbkajm52Q6JL0Y)yGY!6OD~=)oR24-T(9N=kcfyZ1i~ zN8~Sgi*T#){f38Us+XEuT#8Qo&*6ytEiu~+O;)j8RwtUarMus`i2hIgNQO^o%=+TB z!>87zAd?XBshLVzNau6^(2vNdkcx~7$`uWxu6=DXP+#p@%=+`FHq|cyX^XR$o;wzt zGj|H-Pl*Gu6HhhuF715S{$rC$|ErqliMU6{SGn@36`mD6WoH}HU;=Fb-)Qr(>%UMk zy^qeUI=nxI&#CA>r-?wX`tztBO%`%gh2v73+)`t^1LYi#cNqnMeQV(S=JOv5QWkh; zVP9-@>1qOlW=q=7MEEA*HR~vwj_?k;0_t&zgWr{Ooa zu4|ckN|2d71V5_ZM9pmmD>L1XY4sxZfrb{2(PGp!ceN+jmowTRx!l^aYnQAjFu)OX&QTabSC#)3W;_HeVic= z%eq1MDIKgN$uhkZd+MQ84S*{EZb{m7Q-t7%NL7(9q0kCVY|gS+sk`ea<>ChuXk{{V zp#9jrI`pFI>&siEw|fbFoh0B*1|)-U8lP@Fg%OdJl_SJp8ZBl+!*{Kz?{R2CMc80k zdL3P58lL)wU8Zf_`JXEQr^CMfX9De&PX1un6&Pk4IDKoyYxuz_-n^cGdvU30fHo%H zK;3pHyhZ!)?a)}vD$}(AyjA+k57LVQ?8E;i(Ee|%0Q?v16w6muKign-O7UHy@#|rk z4Q>X=*TUlqS9Ku`TkuHw7!tipm5MEDf3=qyBqu2IVaF^=k|`7OvP_F^7?m_6~*e$I|J1G9%{wMl16=1N8T%XQB;7U&TbSJg zV%32Sj12kBDwDWmVy7_DRB(AIh$2Mv#0l(VklA*42_6|K1Ho7OR7HIXz|+(+7e=b3 zRTiD;jlro`=hUpyY8I`0dNg|i<8@;B=Qo! zuind&quFH6s!VFba8NoxDAFisS(=3i1&H#yTw_8IAlE?X_Aqg%kOkF-+M9}bg<^BO z0FBf`VM}o+7-U=s0guLPnK(Fe|GZ_c>e8#Q2h4DJFSSm19mx2Le6R=zDn zV95thHyE~3&~U_R{V|Fh+0QP1ht^?qYGt3umr!<@xFFrlV)>Nl~a#**wX7xs@AS@HE~EP@lv@0Z#}dfFrdoG0XQx(+cDT&Y2kClF!mTtN6qA9nix>{dPbwO41+Qk%Wgp-Yk zeHm&UU=Vem4=Nq1@7?J;ybk@a!HVwR_ef}!LW0HG2oep%rvedpY-2gC%GP*)sCg{m z%dYIuXQ|iiTINP@yU)|?Ws210C(HpplL8nkRm$v+Fy*Tw)*rssTuJf%B!!|6Zn+?V zfhQ}gg(+n8ic#AN?fr2<$=12Mr&Be2{t90}ID7Y0AjSEctlp=1{3Idn@G}&x{6sy3 z-)i!XCN)ZoD(vuHtBOAUqt}u*3LqW>+$Cha6+{dJZ1zga$)UZ;`M_q}@IWcwMxfuVm%BC}Q>x!`f_;?{@Lz8%ZY z|2qQhp9;X=1ls@alE@qFFCKn9-0}0ZApb_^f35)RiHud9=Uwa=$gNKw2|6|-YXU=5 z*ecE4@?m?9$ZA)M~*nTG%2S9 zhIA{<_ia+tf+tE0T|RQs$hrK`LcQxD(a;d{jUM76(TNKxYuO0wxVW8wx;XJ@*!gZV zN3!#VhUj*l$gq~+cybI%u{QgmbtZ!4DL`4gr`tS|JP^TO0R$iIpPyO)=2W%iH<1ua zi5ucM`%0>mR#^9dFB_+0!a?A*wg0;EkYEh0Ce&>DDU``A$ZAMPQ&CFCNgVOSA81nt z_qknoZ+>=idCG+N6(beH?kv4d1aUtf!{2l`?8V`?tfMO&@^4D)GmhvOApQi(H?nNt z%PfjQVrWHtq(a{)WSCoEBQ6EIA-rjcbox>MtfSvC#=jWk(%m8%O!7B)M-IpVTg611 zuyWcF3r*69Kg<&t2ZB#w;Er<8n>F@-*A)Fv=8HOB{nl?+A7%#fZVhQT}f7 zqtjGA9QO!Ff6?&=nRpnd6vCjGrKG-ru`RGr-O!=*3HcXD&u9|G`-!1g{Vm;Myr3GvXXP=MVmWTJM`a1jfc@c3boVa%+OV{UuVh+e1W&e3cwWWf?o^dSsm z;G=#1$RlvB@YF+q+y^1Vxo%Nyc_oXEzqp4^R;SHErkoq$QH!Lje3Uy!5mu_|gnW;uyLBYkVI_@~md~WYpoUE@<{5JL9)- zge39NkzyLIw1K4VODpGLw4D>(DL8njF3%#$rjzGcC-!1Yw>g1*Tz3R3=kc&aC6~}j z6RrJwN}>A+n%Ig&a_v4a6W|PBy)(1)s$-@hFo(c2-Pdw|xX*L63m;_#iTqhpu-Oc1 zsyh?cz(qoAB7#mDqLa>TDqQBsS$m6Nc!(Z0`3v8;^g;B%b;%66D1Vl8osV__nr=-P z4n=H;ij-oZunYikQ2B9QTPDc5v0|rmaOp#2c3OmxLY@GGWI2%-fIE6q>;zTxIRl=W zq64WYY!f2jM)ZvvCtwju8V6(O1sypPUfn8P%h7!&gh;&AZ$#Gshi1@0l;i`aV4#EBl9 zdJk@=0K?>BJWs{@Fy+V)a*|KJPXqJM@7IW>kC{qM z6Rxe4y>hy)ce#NlfBC7|#4x8gsLVtWTOSlf9wnyY@N;atDPs&7q zB7D5GL?HwU>E`j*njQ}0`qc4kCR&aG!KH5%^S=WeTC?W%X6=M#P4ni}We5#u|I^H? zSrmL>6U{-8p{`i|Be+jGpaJfOb=91OjHy*CHe5m=usRf=OSNUIpMfDI0B$(&Z-&_yW}AcDgx3Dkt(p9` zFeyi;???<2hvgzCX~oK>WVw6f9tGT}6gDi3T%3KQL*d5I>1%ffNcVn{wS;U~UkY+~ zF30?7B6I|^38PBcoXOj~QNoUC-u~FPJs_cd=?B@I3i>V~4!c~fT@0hvgCBbGei*)oGF}&alF{5EFq=+c3C+0<*magn3PLA zSOl~g=aErz*%z_yY^*7}e%%t;GUJxB1sKzdcoo*pz9c6$Ovpy}*JI)C$9hVo2i}R|?5O~PixBYY9R>yqfV6;o=y@6{^By(4=kiJ$>;BHZ zasUraP*mdW60*r*h7z0Xa)i9e;z5vD*Rhum(;DpGD!{E#V0MV~jZJQn!X5iT{?ZvZ zHrR2hGrYL`fvy0Ntgww8?W`sE6UF7RY?P!3NIp)w>Cp=}^%FJydo3ROf9{vdDR3%s zGln646P+u-)tKWEQR$y$-V?<&AMEuVTu30zG!0q2wlU#s2Tk}DCMjxBgmw%0RtK_p zNQ&&}f7NhJm)Ghcs*IpL8`xff+4KC6F|>VN#3zC09F=grn&ckA{cedbYa0G&>8C2$IsW3eGz5U^ z5*kAQ2%!H4*uc9EpMMK=OqzUHhW}MlVr{2ZQ(oV{ni2!WYsb0&YD!$RU(lveEZ3pi zyDI;w6@sri54j35r~d)OE%d&Kp1O+8$h`E&DJyCudRh}H89*7h4g+!5=2T|DTA|k+ zQkR%re>-LWrh&jsiSEoR7(Zza{(Uc7ef!MT&CMVFXocRaw8_Fv33!^Z5XtZ0)osa( zsA|6kHzk5ph!QfnGcQj@WW64+C!Su1YvC(U~MmEDg^zb~EV4qxY4+K11W-5JkcJN@E>yAwV6Ha^HUhJH4Yq z*gAKi@@*HNSY6~BS|69AU-YS_{P4whs#&tlCn>4f)AfwZ>V63gw!Q>cwf490ROm&o z5sn1OsNr2`LsCjruR?VZZHyJ;{8$P`Lgs}w< zA>0ZhzAgv zA6te5i-~~fnQoE=`quu(*6O0+>vs&vAEOTZSc$$14#IaN6{(hE!REp~){No`CH%3~ zfl59H4Dl}Ua0V=#77FhWe?l?GovG!uj=Y@&6%@~oH-CTecGv@&up2Pji z8fN^0LNt$LwOH~y^8H{-#`Upj*4bH&2mRtS0vw>)5-1brZAFzDnCWz2zM0!QHmWZO56y zDHPhMH{)h_m%caCR{AR&AVw$(LKbdB$UWTt;WAbKQq{=$ui^zs4E4jIC3&=FT81VZ zk^ru~H7tAS&N&{U2A}rwwPlLx-6#_2ihs1Uz{wy@KE@7DfRUzy}X|&#;`I~OAcOZBw zYbwt$koqCWvYt0c#U1-re7Yk*pPXe9q}-xgA6nkeyEmxiaR7|NrdfGSWEhEGd`bim z+_&C~^uk2oL??{)ISbPyWw{E6(*rgpnC2uHdX?FZS6S-F=|)|5r_3<2%;aT`2dauH zM1+;#C?5x|JH${VBm6X0=}K?4YS=j+pP}OxMN8R}FLi<9U@8%KMZBq?+C^mFwQxZW zpxv#_3-O_&pj^-Itv;8R?`hkL=YCV#Bc4}+Mvts^E|=Nso8u?y!uHXZp;cb=eeT@p zdos)78N3;w`uG(fFVXkz*@{XDvyrfQaqYB}ub$_r9shF5I`m&a{=YkAM<2z{w{ZTq zI%S`@7un7{A$_>LpN_wp#b@k)^;hUZkW>ry{)*?TvYW**KV|!%cd90`c)l$DXD^h6 z4@f?~Ht8i=!D8kh0%+>bBa(G1Bl4tll4Zn2{iG#{lkLV!DT*pmNJquK0JCh)flGq&HH)#L0eoAjN(Rws&oU+~7}EmQ~*j*yBB(Z#T}BLvde!?Uxxq-BgwS5HPtm*;M6-#s*ZM zs)#e1uPhgxA_nzPlZhs`YkwHnesl}fH7pg|m0v5W$UmO!ZKqJn#O{wZV0p%TQ5mP( zWdD$x{)nbML(pQtRQZR%m!o}8%c72dRwW;lx+}Xt$63o50GSCJ0>lJJ3AZ;-9V_r2 zRHu69*CFc`_CFtQ3i`e>3wH(H$)ACL*ZMM>HYoCCy|Ekj-=f1Py%f>*`bTYYXERg_ zyZSCQM)fQ{DM)Oql5YpSh7(a?2}D^OD&(4_%K(~Qf>J!&m(R@JF>`X21!0e{ErS^1 zb~V{)E_i9G*UStKR3@sFXR>=ue|sLoFlWLz8z0a*xx~1DG;yTC5AI~cUc^@$Wbp8& z?#%29nUB*Hp0P64zj{J$PznP3N)GOOs|_7NGsu;G2Uj<6gY+3Gy_&tv1@&zhV|u}X zX>QP`yN6rW97q$t>zDQ6_HC>#>Uc|S9a56;J|AuuC_ksx5i1WqQ;}+Hqt}(M)#g%1!9=AF9cx+%5I_0ji*Q}_yzAeO}*$d^Rq%z*E+RiFp zNCX#dCyp*usr+UiHpD~ovEdf2N7bApOF1}8MWjTC0G8Zf0@xS}nSEBin5e^v5002- zNE(g(I7-|i_B4z3t=hdgYnwtkcd@)oPzKKaNhI0xwLWPZt z{FBhc?DE4T2mqFfvgE;JM8q^TE#!SRRW>i{24mUCpTpb_M^Xr?=zW1Gf``$eAXfoo z0uS9|vd^Liqcnl#23hXrc+67VCHo2lH{68U{>~KWc@}950<}yrF8zoT8)?bL;zCkC zuG;4TVcc0bJ0TVE?U|O6+~H|JUeL;^eolUF48=0VdO7$I+6fFk*EK7IPQe`nh_`fk zrERgZ5E(riTq8|FK0zhYND~m)$rj}{i5>+f?us9Ynskh%qZHZXaCj~b%)F-jb5)^0 zIk1(FYoZVicpvq+8M8$eho$3wFoW+?{`6c-Sg0!wQua1DF?EQ+$8M!%S+`-j=Zo%& zV}4Mtv2#n2qo73%hot0{=4Rqd+bxjm;byRmS|UXdz_VPe~SFd>NWavjL(ddxv1 zNLvfie8yFgT+TUbTE_h7`QJmN}4og@jp!lz)Xxe1&Xjg?xL3;#h_9as@@cQq8PV!@p89zEZoiviHN< z&{F}&swApyb+6txIfE1_WK@~NSDBSoS+rMKg;pV&s&aUh7p2!_HsPbW2zYAYI#!Kn zk}-Qw?KM`t#lOb8y;=_b9@d1n&-I^G!?Ph64eyD9YbAgR*GfYD#lg@8MYx6_@VUHE zk0Fo6Q@3dEJsayU{yP=cFx4`A{CCM;zybUI90MVbXx0RfLI!e8;i*-BoLa;k&muln zQKdEl)|h{qJQhbas6Mj~eoezg6;%o_=V|YpF!17{Y^u+`Ot%oyJ1$M;K`vpK$6AhF;=$)wYG&vJ2NdLIZD8v*Ol0LvTxh z0s$#wYXSoWHd?sw}S+4hqJIM$&0W7D@oShBh!Bnl(AdU!ES*#{DGxWwt4YS!I>s zUC06wuv~|O-K`A{ec$+#+wgJBKU>IbNe3eHMh5Ne#nY2h-9|7*m`WbFw?5-%13KYa+q8D1L=TQEDYU)0|*XModW)-i@C%L8#YI5Z|OI`JL}(Lcb4^W|$<@ zyLHp-p1t8c^CyYP(_L8!*8mk6Z;Omm1R9)PT|qCrGl_5LMF@Iz>17&JD9u^1PYu+@ z9P@9@!#njOWFa8MDJ*t_Jk6jp4TS_71gE@a`?9~If0cE7zh!B^m3*~{S@o6Gx|w`m zs%}-RLqF%_*7*Bd|6^t34NQ$lLHv7V#E&T|OWiK}?>mg#qQ&v7!c?D&#{wQS*9`nE zEtdNxTE44?A0R@<5TtayL;ktLa5C?|d3W-Sm6iDiPTV-!<>{Xt#_Rq=YG!^`Q+3h25{$G|D+4sw|$8!Zlo*PX1$3;=u=n! zEiG1-8#vqHvmYfAaIgwjdZ%m)Tp1~4+zDwt>`vIz`&d%mB6cu)&N%S%TW(tK8q?>G zBos~d%m7JltzeQ@rSRcy4WSsWxhsz9@NRsEcNkg1VBLx{A;;zf=jS z?RyXoQX!laG;zZqy&G~1e=?j2?=V(nBBZVoHsWmFWv#u#s>H6c&RncKW-s$;*c!1I zNY}e!*KVh6W+c#($<*E611HNlkPsfyCyo$z|(C%EG;Ho%co6oP-3R<(0q(a zw|x~}p{}NW^4z*FYIHN?{c(5T9Db9}O4PhKW&cK`^|5uDzGFUZd@zl$*?pv!Us-;* zU0ezAT>_Y#ih5F4TX#X1E{S>_g{hlE3z-=zJ=JRLGZ#OONgt2)i8`s^?dJHX8nrv6 zuCXuv;>n~JBK8iOA2<&9v=ndDF0rw5x%7qZ&>B2?{U6kbf2)lA)%pEzX)*jEc6%ih z#z|Oz*Awi1XMcD4D(a84IJc)u&<*w8uc7VY%g^37KvdM-m;I--`2SR8MDkWa>i!#F zjGUGmZq2`Z@~175-|T+lqAn!-(-zUFTX>WEkG4n^#VS)WU;q7|w#cje&+^^Ir~a@; z`{1_7WI4k%oy!eZBm1qVVWGtg+z4Tj0LcVr{azJ{ZGwRfb=^NnPe}<=K}cOE z6`^nU?X7||rRBCwh<&Oog4A7DMwVrUY$|wQ$t1z!3xElMlKGpH72J-`iP^wh8-eoN zB2Gjo)|3SUA*EJIvbM}ukP}wA(Fg$4kbssnl}0fdJdceoIWwyC9#Z*NwPHPc{Y4yeM7cNN61pk(24CLUsGq^)#I zfe?g}EsJJTKCZIJ&ysG*?zRrSkf!nqXYo5q3=F~*jS>eVd@3=#E(nL>AZ1^%)9}^b zR9q%-R?U5ztmD^j;2gtQ3H-=-CkhD*r#*NoD+S_%)#%d_&jjg+!MiHcZMf61qrJO! z_Qa*GFz}OI1r~TdHc~r<<^{2&Sd6oFOz~B(XegkFD#kxm$98-YKJ1P)D5p%|tYLdl^J?#9E@HPOWk@^&i}Fy(;ihdM&A!2;vt%7orJi4I6{=QWGg|S z0Hpx0veIWbts5mzU;-}1?`f}ftoQ?Czd;cX9vN7e^yrcHT=;pZ-aT&0?z%yvl2F!h z^O_5p+I$-%RM%^ne#ZHzHoo3v^&qLck5v9GsK`sHew7Oyc^JztGdpsQ@jEp^%XH2%}rNYCk5b@(T!hynv$65mzK6NZQEwmwpg1$!^-PVD6zP!5ibhh>v~JGAWPy) zZrA6)1>LdLT;WXJ--8s)M7;o_lCan9lptB|?8mUT&7^dtFTD5r-*!mPKU7l{#yS9} zS$@h)k<`bhtHUR)g&5R?SKommG=>{7!3)eh?63>TV=Rk z6^%d?gU!H*buTsgnDods4f3JI?z!yFQ|l@h)!MhGe?>wcbXM8-yM4_)u|2h2KVfMg zecS4iUbm0y%a#U1JX%U$41P4~SQ0*D=C_njx=otBTzVAysO8+k;H1^hrN{rEMoif% zEc3EGS}RvQoN_c@{uedEW&85el1DH>?cpa6SWo<~%1GJrKc&V0Rb|8{_ zdQCDq^sB2aS-=NF+LMT#FrK#DeCSjDJosyttR%&i*Img%X}Z{L?lpX!*S+ZunK$FA zhD2iS_1@CkLGCAf=Wi98AIp3YsZ60LfMdPZ-tZT5ER9np3|1Wf_S*i$90zcDSW|+| zJ+qR;lDTZ@3vyb#Yd=bJhDcmXvwWDKk}Cd@bCcu^xIcf7e_G?arc)* zLqhDqZ3wgAhK9=_-8J7T4kp@fFIt;*1So6s5?9jXufv4~$DG69cMuWDa@0qsQcaGi zfuGIznY}{t*pcUxQI~E=z9ljbH9S=L9r9i{>Be&G-Gt+`}PD3terXVnq3erumLfPa6Y2n*LPkw(QuA65x7CP}_+3+iyANv(uhu zk<}Imc0b4;SQ__(Z608cbbQa%nQ-Kf1iN$5R$TE%CK-87$-}*oULX?I);xhVAUx73 z?eHs8sk4-W)%bmJcOw;2@;M(TU^jt4!MWX%DGMMG+>EN|=;HWZKg@DI~?TXcMLdAxwL+O@t&&iy~oKXw}>w-|u-} z*ZDin^SZD5IPTwl-2cGju#DIH^?E)Z554NsV_j5(rrg6@(7w*#5Dg6G(gGn$xauj( zbTYit;$Vk`nz=aSauD*VLKZWTL@;_}!5qiKr*SD8Xm@R zd=0hc*#*olY|03};xsCSDtd{h_{3adzbeL*jj&-OTHao4kpnEaN04NcVBidvjOr-` z^*Q_YqV%A)i>f0Se?dKhjL}aO88}^nHo|E!U>|seSayu0u)a9DVW|5E! zFT&QtiCocyfza#PB`=SG_1fT1N*?ho-dT>&+eugl03Bbb0tOp3ALcue#|;JHnun*D zB0}CNl!N8A+hOO`vi;RAWNCxH=c5lgg9W20mt5l{r(N%zEBg;>L|7_H=VsYk_&=x- zR(GX$-uXYJMr^Rc>xS+Uy4z)&$ z1VJcR3M{RtI^7CPhor?BOVv5@HL?`=G0vXcTfzBss0jndsKQmqU~!RzIt2#MY7PyC zra~DDK3tIvy6<+AlL&&d_vEG47_wndVE~RKprXa}!OhWoBgEwhWbO0lymRGbpb{5$ zE92^1Gl5_Ny_tam6OkRUr#&m+mu?54N(lsKsDx3I^SaJJgEm+|kfS>5P=EoJGxmiu zj3;f4A;% zZSCz|#}7XPj?$sy^{$oEyP)fMqyRt;M&!uW6CYP5hSxXif%7zoTmeUuw??tDWQ4y6 z(jW|i@aj;mnN>wCux?0MUpIKSwX>5jB7=cW(HdsKv~-a~3Sh!T(V*=YgfZq5UZ*uI z;lk3X*sFJ8+T9ic2BDDx=#tSW7Kjoc_ijc)3=?T;@>cD`{6S2nAocvVChE~6hLFsf zg%aDNcG?Gz!;@-Ac6TBJ#h%n*(-e5RY>rbl%+Q9K5ruk8< z?N?nyk4DMqFG4POE&!^QB=jK<18^knFsl2e)4hhP8CP9R!L`c-YdUa{QjRoIi=zYj zTtc&y#eLMB<-4J~6mDs61u2gR>$bP_tATz$k#MGnp0LTeVDD`>^Y-zLP5195Ag3D! zE&`1v2xJ~W;Gw@RiRWrRIElK?I#>H;`JUm|ymeQJ2ri%xu^`CszuPN9`Vs5udwP#= z)MUCvwLe&wi6K*fPS9eJEGh!6gc0_}*|iNj<2A3WLCutIEcx69J&%$-*z|dyauWl378$lpP$1a1=bo&x1pk|=L_o2 zX576xSPRBLrIo8PT0Ilovsl%uAt8Znr&DW+^gu19MV=y%C*}gW1|2&Pro zjrJb3NUO6l)%rnCxc?GtNPzkLOR%AtmaFvdG$+Kn`Q6%7HgFVfBEr$E_Ut&3d&O!)5-MetYuu zPuUzI7k%QD@BgGtDY<7G+l$hXW@i3bJwOPEL$hx5V`DErcERq{FF~t^$An#-D=W(j zri0J_4mO~5_)MfsC_e#etMC&cU?m^YoahWEOKk})_2vgwmxc{HkGx7HZ-AcJE*vQc z0nvs|HbmSk*zI$m1>0u`t56-y-gZ`lC+jar8O`-X_4%D1ev1CzLO|>}7d8$dAfRAF z#H}ym7a34nr8xR^*aW0GfmRPEenD*&CR*<^J6R_Db7?xXdML{>oBUkPa{YsVI8&2r zcNPLxZdwjJ{-qL$_jy8rpTy}gwLqysd&Gs~lP3#t!aw{7&gA4(;2Fe^xHO_i7W=TE zH^u3&8pwC-mbp6h4`8L07PaZ|CL;4@|6jn$jAK0x^Pm(QcyG8b-O*SKh%hvza0gYd&H{`H(GAa> z_gilG4`5~V`DHr@Soyxq<3E9w|E8_-|26$iT$}%JVqW-d{v#7(xWG@AJqVe8wXZLX zWSM_o7-ju8nv?5R1NDX)l!?N`K$iVC&XU#mrC;GZyJgPoa}(i0)biLJ*&n(;R%lhv z>~8=ZwEeWn)?-s$6Azx-Kfbt*D=+HqVDt0Uu3l@qg_Y5`*~}H6ESR;2O8j^DnvXUb zE5+@(QosTiIrc;0N3Q)0g1YoAOIrvej8HftIteAIM=#Vt5U-D20bUZ_1q7;>8#lx}qkRmZ=9$^wv*7T)2IlZSSx-iz)oSf_IKNJx@`d74dq3u zo4zM3Ck7Hj$Wfp~DGR`mx$xM~Hnb4k?)fFj%GgG3=}C8P+*rE`pPsztLu+mfb~j27 z+ip?j%>*@gVH_YXqnJ5IYhO69-zxYROslxOqHD|R@k_Jdd=hnungv%C7(sFvh(kmrZr>ww8Z z)fqU&DZbE0d4`p&vkH4|)^i2dY#^^s*qsG%G9*&SU8K`}YT2>8VzQzRq=|Vtsrlo| z3) zqW;Tsdkg6dL51}@4TlpT%s)@pZB*|TioF;F*f8--ccg}-D%O$1Q7bd3`;Lac-3pS6 ze{s4I?XqwBUq@g1_;i~l^!oWaIQ$?cy!8n*3{IrIX zL&3_yfrdmKYg0|B1S}QHU02}^_6{YWO*l!!THbSjFVnOF{!n?R2|b&cU~nAJH!x84;<78GH%D$nXGsPumHE+^)l_ z$5FW8H7dVBtPY&_@|bNYLNz@Jzmttn7J~`J{WyEK$h8qZq^^w@Qc&63@E4U z@(EbVm39WCXv{?Ws;*RkuMSjWsoGp40-f(j+Q;T1&XLpP1yH`5)qX}dF}Dd#Re?8l zlTLMGt%L~(#Kdq?4W zU^>brQ@7XT#LeL*ZiLhik@` z41i%=Jn_hUi*YC;g!li-d4}RT# z{`-5JaG6hd_+X*iYjx(LaOJbt!=*RRSAX3T{ubmuT$%6^F1-`3E)hiN%HPipF)^>gVnj_SQsU-rjam1x33z-AQP0Y z8k->U0Es+Iu`z(5tP#z(Ix`=PQx&yZFjE7t>1?Zf4t7Vg$vMMiZroTqI!^N^xyvnif$TRn}*HFESx4nc$Iy2pK%Gth%l{ z_8AqJMdyor9q&ujFgQc^*x{SdNauI(bXhXrD)C;>S6H&nrXoFWPs|^xSNBC)S#&m$ z-z&W~q-NV6s+WyJ6#S;h)aK6Ub9ydmEdvh1E=etor(Zt`--%eBfDIf8aB#Wbmn3e+ zrzeS8r+5D`*Nr;^MSFIi)`kU2a%Ft)YrBb?bR-}pozfFrAamVk*$9}FIZN`Mh*T$0 zGMRxOg?Cg#4D#^3PnZbPQX~;(;GKY0j20l%Y|Xw@Y^I_?PasJLzQM5GAkq=(Udijq zr>8Ey)Puu_OtS`HR#fLu6QvEQ+XG7}jDCIRj3O1u#@i!mCf1v9PYkEZtQp&TZheea zZKz8?am5ZmFwlrm9;+};SL{@Df^Jd_ZY_Cw`WXtij%0VNf6M&tV3Ipt2ny|-Rp{qbPs*Vi8p0gQowiGWg{O^ttg037x~GjZZT@vHu$k^8eG3ZldYAUEbD%mK&Em>=r*Q{Z&^!@a)*# zf3%e~Acq}X=TBSN$-EbG5^CL*Z1IR zymj`P)c4-DHryIERQ`KDJqoqDaC&xqeAz2?jk(2@$mgreg6_4#mAN;E{+H%DYNBRY z!oM@u3H~6)v5>h=vPh7u1M$AL_O!{|6{JAAI0F-(e(HI2qOM%pp5NwP5r8sh(}8x{n7z9CZ?~ob5@o-^qhe z2>NLwQWIm}<&X;&4kZX3*EJ(#!m+VY<>NX`g$6EC%hy4i4rq%Lt)9irC7rvb<0$>> z*wdhXCxtKcPQ%Gk!XYS95KBvv7myPq`9XSWCso(~?DL4G8sk8vF1tZ*Z&w~7JLvz_*a0G>-vRH{p_w3*b{54DQhgQGbE*d*K*9_Az+4(PIz zh()Fk9|UUFMN7HcJ&DXPugjN((bLGYFhBo@V0rJ~Y4+cB2=P=$z>Akhdy5?iDRPok z)uB>eMdqHt%_-d#w3{t>6JnkO7mo6|2>01)8R3jXoztgo`=!2|Q*24n_Z5u2mfO8Y z)4_`U3odJihI8G{sl!E}FEBRfON^K1WDjAiSB)?cdXg&n7uCNZ<#Rl_ZHo8TK;O-r zG#zS?#*UMh*JUT}h{QSP{~9=`*?6aF_`7<3(HQhg8z#gDwi9~Y-H>YRRN~Xew+58b zZI9pE<+5a6I{d0zy#|&UPNTx&m~R}uy%7x&+jH_E<)bHX)$%uv`S3*VwNs1r?_&)7 z#kaE^b57lQIH-oSBM%2BYd?7}d+((RaH)L!m(kmAwXz**t`~si&F^!7b1{pbt{;7u z_r6qqtCBF*Fv(%Bq;k37ZqSt-z*Iu6+U&gWA?{VN*0jXX;Xt6nBL!kEs<0o18b%$c(-1S{*s zXQ~IcocL6gY=h#;iK$Am5KrH7Jac$Q$XtWf$egffb?OxPi|x3?xWW(1Q@`DN#3Q&# z#r;R03jNz*IRFe}K}Ee3xY=}k$@S3(2>zjMN#daxg&wljPruQaH$Z~7e=td(N;O%9 z<(@<~_lchS4wDTNO&kIUHm%oHFdAg(EWR@TW@f%NbKiSKYbJ@*T2Z33#XMw`FtFfe z3+Ll$Vq|%(D@HdCO*O96EuCr=QZv537$877@~3b8TX9-_`1lqGjn$KqdjI{-c`0uy z497Hw(-S55WMEbhYchFaR7utwL(8@5kEFawNDe~i^W7|CpE4NBE$M~Wdjs};6E9j1 zO0K1ITe|ap5d9X@SYtQET&ds=Uoxzn4_wmrbdFv4{e#}sg?rYHvy7$!((VZM>DaIF z79Vn93qPqd5`e!3OiVY{Dd%X^jB<#1d)cVZB%FhbsVNO;3>n!av#i9{kxIQ^M5_kiTfJ; zJ<@&ry@_iaIES*k<$}Vx_}^4LH1A9uIWC-Mo-IEWXmWgKL4>H(Ki7f&fK!uT>;GlM z>S6KE{kyH1Q-OiWQ+>(vvQ;+Y)&QAW#cwx4NZ*&7aiVWc|X(CUWr@Lcg ze^scbu^#X4E;QaQ6~d8j)$%jR3|R`+`vk;02i!%VHk>mk4_3IZ2)Owi9zuq|5GlRq z3LBCTR~)VNNalWyqPw1*;GcW_w4AVJ&HoaddNPjjeRQk1?3e2+%bPyIyP>U_FZr&; z#7CyXH~7b0n~*fcgd-;tQVt(CYUTggnhpP7tpiy?O`vpWYo_+iN$WzW>t9Wvj*yFO ze>H(tjCsY;AzLb`P!lK{+MnqLvV~2Jm8DOhCeWX)S=f=&2EJb^{?fb@$4q{ydZz@e zH)o#Xv9)-}Bj|9Y)?y!Pw$mS2;Q<^`<}ZO#7DylDNkHM=*Y z`s}~dy!@Aeo$>!>#G3Aq+8Qz4N!nL8-KF@Cz|P@{Q_6dCJ2K__pV_Y#4+)BNMaKx% zLVCGpnb^nj*=JUS=vfnFo!~jNg|eCJL%Bq8B@_lu3$zdi)PDB+U}(MSD8=dL7IM)H zoMr(S=q%w{aNyQkj}_2a-V)%n+fS?*X8`7q%b6H5tACzK_$?g2{V|Z~kRtCT1)}X| zJA9s_$O0&N1z@~Uk(u6}i~DINFt>O6hJ3tig@6x}5JsK9F?O!X6E&VJ%SkdD>OnlW zZy+%{Ww%rP50xVChb-WGyIO=kWW0{dFb7t zKIgANQ%-oxu4riVUU3hiD!wFaPDCDdhNXO;z2)mHy?sxqt-#MD&y@gJ!0qSya!>Kp zB=d*etlcSqC=)_zQ>e%x4oYv&^Bv0r-P9RX*7B!Aryefu9LCG$#x1C;d~QtEOzp~D z-^@iqp%F_%0bt1}#obtcR`vnq?2)Fnq^0dUWQ4WkmRt9)DgWZS*)JL8#(i#+d&P5w z{dRECyA=$m(wu<9p|uB^kXYM@PJ#f_V!&`nPIVfxg>wldYrK`m(%aWSZJ(F{C#9Kz zZbdNx@?|MbZ)fO+=S#y*{UUkk?bf>`jomB7o;fM^vt9MuT60g-O^E@FODoL_y35X; z*^2^I@M(Hi`_o`$ih91n@-RM#G9v#QcrT9@AWfMeb6-^DL_PBJ$a>~XG;_)_Q` zk7RnRxQ8fs4G^N5%ZNYxlOVNOnwGQbsmeBtlbW~G$(07_Gw<5uTGN_K6phcyd4$-{ zB;dFEj*2xkY2qC|b(`WUvdA_R>jkp(;|feFRXe3*DCr6|Mb7TKk+p}bNqNm-SD?04EELHW1$#r))#TRi zTY;alU*og!o%`mPj64Pci}3h%nkN<_xFUKa)aDf3$2VL30_x5%wU&bRTnScLCCOWI zXvAd0>GM_1j`%>gZb>cE(u1$kY^f8z7O@5Sm4_3l{zfcUBvTYhtB=Ad={q=yGIiA{ zI#~VuTi-`Hdri9`elt@{Nd6vjYH!;9{A0PXJtmiw{b=s?XHj=R2l7J-+Hr)QmLs2l zmDG#S3%chVRhKAYN#ec>56Ldo#g!hYFmPV8-8)08TIL(&ssx*xQi7%ujzep;5im_* z#H6m)K;P=wHVcJ1Xq0T`YODqk3U#BEA70bk5p?8q)L7EG5`UEb3NJ~yBLQvBb0Wj@ z(p}gN_}3keiU#{S{FelnO|k8}tyxKmY$|YsR=)8^FNSDX5{Eh7y! zfFM2q#OT}+p@?)kSMrh|QHco?gQX`?$0vyU$7+=AOyIJ|^B;nD9iAae+n7qyZ}a11DLQ$Hl*{yF?3_#``A|V;`0#DoApYonKj$^)8BETj7gr8%j8!zy(YZ z)Fiod8J$}qOk9T&Q`1Imz@d0ZVKa>xu`(L6XBAcvnUYen)1mXuho90}4T(S<7pc!f z=oEk{>$EWV9oO4!SG@xgN1L~tA5J80dx9KDu57VYbx=X>o=QaIT6}a$1ju<9n9hRg zoxXlQk7l;Z6{+BCZLQJOT6VH|^s%Bt&2^lpPxnM+kd1bh;lQK>pg%!~g}LVthj@uH z&8;Gj0!S80n|`iw_Y(JLUfY&)m7Q!6G@&kfZ=l=rSHs2MQx@>0&gR0yP4|9(V>~~t zgG?OH4pQ8GH0R!j`DgPFmVf_X5?c5euZ1>+RYAH}%ZTjrg)ZyWX;yB_n6}qq@AlQ1 z!sjjH=Fb>lL@IcEg2TZU#D ztNxyH^gxeJje~HDl(xSYNjs-BDFKcu2O}=*-{W%ikIYW~(*z-?9(V_jz1x+mQV)3d z|25@w8U&!*yv+n}xoVr>flEK9KH49B^ch(VM{z#>DLvx>=UOVciZ?ylHIXS~j_|gF|8J+JJP~Hh{y=|m zVmEoCFE2sKx`mm9H=cVll1p9Z=L#&RtMhb+S?wFwJ}P!-MVNE*5Ck(Z2_}(%g7EN` zI~-{8qeDcdN*k6)#gI-=lNCbeK(1`SVdyrfi;@8pYKD9~q3?D``{2Z2I*1&mOAO0& z_SJkYQ%lMBT)UI&Eka zi_YP<1*!TuGZsYLfbAMEw5(r;?pIDnuavf|=O!7c@DdqFW`}vZ7*032g86pSO}cMu zXZ`Td)gR&f=*|2G!1CEc2{CABk@OeN4y8WD@q5@(Q!Pn&dAd_pZ%bXI z7d2XjDk1E>Fx~b4o6PRNS|ojYW4GLMVE(<%7bo-gu}Q-1Pbh~Z0*-zhsHL*7uqI9L zV=^)GIaLER+4O$F=0o%Cyk&%!eb%m=17aUz4WaeX`FlN%Rp+lSP3o$Yogt@k?1ofR zn=eUfobETYW~6G&V6JHoGustUPkoU8mf0`ycS?Cy&XT~yv#`5Y!h7C0aPLMoZ&?X}cA6P&2=Bk$a4AOa4$w4TljuLfiD$ldRGA{odxh?0!yFn7t zFgE-?e9THP9!3HH3qkI2F{JY3f}0MQM@_b%DZ=WMVWP3zQ%&WD_zomM<)uOjDCO06 z&!5uYRT(7#xDg5yrpN@4st|C64zoFt zj$Z>Q?mYZ012bsn<5bHnqQUTS_)`R^t7RIktbPW~;RB&^T4JBo~mQu5Oxy~J~II1$u$J;Cz z;dRNtnSK#5I{YQl5S#_}Ta?SZbhq z09;;-ee2ujp}-$sh9+htnDwZ?Q$D<~T|)+T8i*!Iviv(Vkdhf*$qOBS zq;rnLK}pFLKq|;wHi$UurN-BIqQI3PZ4ADGbv&m1$Vq9HdQaK-N=#>C&lkx&s|3m- zx$|*J-qqdK1>8fu{?8hAHk5ucjI*p+zuNHsB$m8wXY-nL+Y{LRdNW3m-xwa&q?+(u z3f2H#G0l9n6~DWDNtu@uvvaf*hHajIcr_;L7HV^@Xf+cBlDccn9ljqvlqgvSqEOD< z+*5T-_!$tT>AoZR_`7=_Jm`)RY#tiHVjHfcci}$rjl7AU_?U?{nHK;WQ4AuH=SDVoSm{YqKI29gRPJG8~R!6cBR@DyT zPBZ}gz|<^QYvrxJDNd%Cz8O&njQnJ{nUW&2V^`LRA*!h&8VmqSVvBUYgPZ-yQIVNu5rOw(rE$c%hitU@n8T9X z(x}SH0;Hcidp_0jcm*jfkqCPIe6bZjxVV6^Ak}9afdmk_vSfWmUUc zCH@ux3YhpRhuCaa6|3&ZKz@`K@8C3_;FnDBE%1jfj4s`TCK`5LATnNs-o%W`sayl& z>b`=Lwo_4ITohUmF9aeV?2Yg>ae6o>`jB@@h(YZ9Ho=q5JkmHL7Qr6(ou#lHx8Vj%~hE%3z#!dnph(# znygwPg}E6CuBS=)LwRAQj`~ehg!b_r3xp)Z7Wcxf6=Yyy>*n1}Vm+-WEKD5kAif$T z{gn*1HXNo2p+8m@N*jAB7`r9TI2zcRy6OgT;#6ZK4Z75WM21P$W5`>ZrLTcVQ;W?e z185O8e3`Z}=4ga_`bjwxoE#SAPmjAgn|`exU(=kybU=l(X~Sn7INf*yck{DO=6EUG z#dJ+|XOvVhvKE$ATL}I3Wk6ZTQDVeAXLDR^X8Z!#EY#+BfgF@N2xP^~<)Jsw0Bt@T z%Y}eUHidg4&W=(qLnTBVgR|$d1N=At{sp-65V{m#Eqx=;)%-+g{6P=}SbA^jk}XY) zY?U;i3&>hk=#FHO6>jnhhw!}lv^OKFMaPxS744*oZUlkXd-K{B5{l2{F(ptNgiMSK zRDrpYEZ3hlA&W}ZNm($#!ax{gqbi&}W`IFO)8JD5PAi{ti~Z$vEuDGiUEuWyxCExE zTK4Nix(7R7pSJOKVFJ^CYZ(yLBOv76J_Vj>;CkL2e1ydUqOy z@n#%vE%0NbA-tOf?_hImyzP;*115P9=jDP#NUbAiDh06So-ek@lRY1)25BUq%RTMz zCPvQX%9y$yBox$KBS4o7gzI(dn^Y$>bgelDyKwu~MJSg1VDTbXuDC7ChHX*Yb*#AO zLUC`HOmcJav&CYbT*(W|lKy~_*T+f*E|d)3DH(cO@?o)rFL!A~XnAQY;L`Z9OaEMY z7RX(m`K$E&>)7Rm3zwI^glxTaIbI8Xl7HD2jgV(c!t}x@3>XXy5K+x2|G7;p2zT}z z8^+p?EZqg~3&PaHnPBM|w7nGM=sS*yXbMCPixX8#3uMZW^)66DS&g>~5oCFT0+zEu zJ*zN-|-wv;>|ME!d;n4rPRrG&$NB;yk|2)!c()U8w{(o6TYyMe9-DmR+ysNapmmhXS zn?Too?U4G6f>^<*%N_ErXNtqQ|ZT)Cck@9RnwtNFR(mhZ>?$?R@jDEZ_#gssl4X->WgZs#u*IkkGYEj1Hd|$b{qhR zvC@mK`rd=&Ua-r1h}qPadlWXAjmEy*ra zf1C%&fDaBj|9ou?6J@a{5BlEd(ieruROK8iAqeL}k#}0|g`fQhFKbxK=5G5*sS1Ym z)aUYNNPUhqrL|IigjElm74soI zxksz@HG_;v2wo*jr*oB+uymaL)KqyRr2BSCtY`JViv%LnY!5&Bwyvb$C5Ec>N7of~ z0B0=5akX6S5E}oq4ccxD;FKU&K)Z0kN6Rk!>b<6ShmPtU7!vXWpW8QzF_BnNQvVMf zU`*hO1uR%SmN2RNgcnmQ3Y4*p(ks!Q7W&&E57!e`BG3{Yya|9x>*8h;Ei`}_*qrBt zY!Mniw_U2f7X6N+plSWdLj8RXLbAgfdcA=l7Z_7v0DyFJ9*P)lV+5>Sws~mPodfy6 zXbh+O)sI*DVO-)ComMIh`f!kfavE@y>4#3GVs!cGq)T&v7H3&n^OO)PH!6_Gtv^CX zZ_>dcUU5^_FoMuz5>xCuEVssGZCFGj+nZu>d)?Ed;20NXN+pB+A6D6?=Bi zt?vc8T?_s~J8_SXs?aD)=|uvXZ~PI4WF%@cjS}Hs%I8*NA6=$X_9Ry**z?`fV99jF z*2k$ZNB)C=1*iBufmbxQ*W{bvH><2~DV9!SK@ws$72cE^Jod|zT^rUFo^4VwirnpC zcC#<0`CT!BKTL=jb1G5|O#(vtawl%)otdouXlA5qc~;5z!b*>#q!n3cUw_d^_T=Tqm%KS#PBriN`U>d66u3Xy^SsM9V6aLH0^rw(M9D{~wn zu2(|w#CG?WDU(ZWKZW$p0I)ogDA3;K(AaQ%^P@ZsLg=-2m7e1-00GXgZg={X5nP_L z0eox3{YTd~%+$6l{k-9}C_~5mKOs{MJiQ)sds*A~ZM*U+*YILlm3G#S^P9$Rx}w`R zzJEA8rLqp>8d-$AkN@3{BC_DHF_ZV37S2l+uu=B+hI36xR052h9F<8aRa@a>pbZmB zjDj!u*$zn4+7A>xmL|HY;$n)K=1Y+|t8#q2N{AtNo0_twx)d&=<7VF<=_JVn2piJd z7%b6_VJfVHkj^!#9mdCwm4|D_BBV(D>|uDHDJ|9raSN8=UYMj3)YyuUnoiQPXzlEk zbC<@?z0;#5h;Hm^SGory9Ab_NrFt3N_8CTiJcWhdO5=k4w9;XGx9N5UBI|xV;oX5G z2_CguS=9(YF(Cp76M&6iQ6EFY9YZ6tbIaKw5}8>lv!A=|(<3nldy-VTEfPgu-^{g? z;)|$k;aAH~qi-m7i25EooQW!7N?c9Kb*oHW(+11FtC^D#Hv|KiAX#f4PH`N|B;esW z)nfZBw$tb`FIvV=t{e|t`Rr!5(n?q_HKII2PlFC5Bf(Rf#i3r&*sWnqn?(vPxXbK@ z$hDj}ot)h0cWywFMCL9eP%gCSf*CN=HvEX)oD6sPT&4+NXEz}{;Bq!RBM$P zh8wh%$dz;}2ULZ$q(zBtx;_S# zOOb53o1pt;iFHTWHi0h#7@MHd@X!95XY3#X&^Bcjjkpj%p2_Jyp*)xYBvVvfIMKB0 z2OSSO@f94@w@GS?RNJZL2X#{|MP6Oky-FK4YocQ%cKZA*;qORDNS(HD)_Rm|fLGbE zwHbx(L&hD_v+s#br4;sI8%PzB8v=|n?~v219W#QQ-*sF6oIcVzJE|;ZeXKY0()^n} z849aREn(bE8tS9A^Z0e)aOWmc;?B$n=q!gB@T+P($uJmBnOLosTnlayQv;;8qP8$k z_|+fSB!HN=G^oA!TaxgLX~t9oU6M}5s2>lckXO#@2Jq<)EZHh94hEufBv6}x=x3ma zGk|oUBOA=5PMt#qa#7#X#Dx&;iOW3ebMoiJfrV}c`pkjnZPGD8B7Jo6HUSozJ~xiX z)(h}I9mV2!#A~;SZ*Cp%=ADq|BE+GGFng`}ETPyucF@gHDK);JOaZYD+X;$yQbhBZ za7h8OIRq0Oi>v%aSmcU?vK8e%6Ycke_>)7?Jh<&&^l8mhXY(`y`}`?a;TydiRgu>; zu?#ZCTmX;+a0r!kjEarc!BjK$+~%TP`-0zXLG_lRA#Bn?I$+Hp{1lk8_a*qzQ!kDL z$K;{UfPg0#sZNC{(J^ZU@JKo)fr{PELS`^T84Q#k`;_6pNf-xp(?W3*8*Rb@&L=tF zxy?91J$|xKe*+tNm<1DjbV*glW#?=x?1LzztmAT)a&$Y5e{LM?tHf!<4=p^5K-YEMu}(p zA_QSg24fhQNCxI?%%RhLySEEa{uE#zgCJIYGEDd;QN|esQN(Nkvh5!zdcHqT&L=2? zPDM%3U~D(QuKDmjsU$iJWy?U>4(EAHGyIzO9EO-t6fv0|>0y7{;1EZ^-_gHxzb_MI z`^d&T6=j8H&HJSIRZGWWAd;E;K>>>Y`Q+1|d;EYy{<=HvI^+!uuqy zB$RD^Veps2f`AL>j$J5}lRA}mq4@2EON$rSaz$m9MHK->mB)&zFBH|@DXM#0bbYai zBX_aE@?ulK#aj@K`NGA!cmC;-W?9@3@Yf^Fa$C!8$wc-hPN)7k2mwVd>9;I-9Z)iG ztYk2t1a9QlB&`oospW+X7?FBuJm3<-2qtR;lcT~g1vJ75wR40-bwKe6;6>#V+tNB!>#&XzfOju@$KovfA2Yg9j zlPpER>j8>CamQbn?wT*(rdQG6!bWeaSVIiAq5&VG;1C4eqzgaIJ-EU}#1{c@4*IPS zGR2bEzNInwPZ%S9aukEK}g6vk;ETghp}z9u1&>b)f_@d));90J+Q=Cugc|j7@GE&$zC9n{cEY&*B4H z^Mm0*AyUV(D;m*@I+eBUwFu6Q=>YcXaUalvAm9Hh?0yq#?+FexF zaI@~Id|6HONwHD*R)i|D6~z#^RB(;fn}EA|LPs~$pfj!`j1t6%2pk!6h)hM4LJDv+ z)R)jiCq&gY7$|Iyg`Dz_Z_fX`d4L9J1jF^A_AOg}7Y_Q7+R;`uji0Via16t!U1&B| z6)MZp2nXgx;uL^g;bkypRKnLVY(4*=+aA*r(swJm=pu10bp-+>NE06tXfKJTH0$z zN}5pms&x{HtnJdyl1?XF|2d+62Ot5a@T`CHXfJh2`KJ7DfKSk6b*#&#vrG3$2n2je zoT4fp|DTWcA&9MG5}pxYhT?x z1m(vVqrFdiGr2?A6W{+_R@ZtwlnsU}dn{C8bNhgnkt!AfxJ^{vRZMG!aMB90LC<<( z|A@Dph;!PIc>86w<>1Emn^nSIbAp3U+<$rbK<M{itPN63x0Q(XN z<}58d=auF9Vh1(cn6e0y`LrM$F&&q_S;hBnU$$AIC;AT9jjm`nsbl~FpNbe zQwRButP*FWke!*Gb3FX&u5>goN!{ex@!S+~MGm0MgH5>sx3#SOugeaTsOyj->MThF zsy(Y=U|XtIb;gD!l+=wfCy)eN0X6`gXhtU?A|&tIy-1@t+QmaMW8X^-N{#Kl$jA9^ z1j4wmZiO9f`x$}SwVTm7b22NH#OKNFn}9*aORT*2oIXqXY(=}cRJ%FaU$QG{z&q8$RcIQXh^B(@$XOOJ*8ZciqV+V_o)(oAZ&;}7rjqa)0 z{-gH;I%+52+dC?YmL$@YV*m$d(3N(;%)iz~DvIblk)LZ;PftjZH-wj_DW9h9PE!hG z2qh-oGWVbTx8!e z6R}naqJ2bc>1KqXWfK>rIOf^9!7(wR?vWZ@zCe;mMOnVD#wBi3-7jQovuIfu3VVASAU615dOHwNddTndc{UPN{IHW@y~ z%Z=PE(G@B?)NbZ~aZ;JViAbQ%+)4Cx$PE)2)mj^!8<#$*c7@Vo1t+H_@WRMhv`^a% zB!E5slP1~QK2e7_wKXRi&c?R5-+)uONi5aa(4aR_V6&YoZ6kR@-3A>5GsD|<45#O- zW+B#w3j>iw3>d~VC7@`(d)w1h8(>sg zI3@OU4XW&M0@LTx<$gDP)Qe3ilotV^u>nBkFg_uxm0a+7pYBUZYFU^FLh zJ6+bEbsf@((}`P@ZuT3s)Pe3lornjIp4%1Ceg+ZnC4?@KV-j1cAMtKy>Oo9$$|^*b z{t`%D^Fm*!bd4Mjyxx9-BU&heycU<>^56>ggOV8T8{Ut~*v#$xwLn_hJ2CHB2u!fst>>meGeCYZ^XCe>=j(epv6US!6h< zwa{u4_DNsWWB6j-o7&WE!>9C%Wm+W1vJ}TRdOR(-D!ryrv(Nz4=r$e!?~$~>`5(Fv z8WnKbWVF-bTzZ!7iw?!*1@#*X7=?|JB`S@xij=}0v+O5h3DxS4VCk6Zn25TQyv9fV zW?1`?R?uX}1#;%+$a9uiW2YI5Bt%f_nGT!r$^uJa@8vlGRiL*|_tsmeO@%G^@nj;& z!2db?bmXOFkIz59U*M(ZR8v1F0($DlpB#%f_EFyS#mQ&snRV)68{XLGjlsvBH%OnW zYFr74WgO>~KWnHQ&C2z?E!Qhx9Jy?|hUNL#s+*0zQhn%Ku!frL{PJMMn#0?UZqp#P03-*tC*X<>fUNEit?T~iCz&*30i5qP{ z?Z2wfx(+nI>g_vq6ruV4S1RNFwGy=*Kde7mMZ$b{`ep@5Igy2Ei%mJEEP45k_feJ*#_x|t%i$L zwOqFJD2Bw(Zc_6me;~Q@l7eS1T?{dmbU+qrpGilBg^*JzJukDrOH}wE^}SWFTMn8Y zsnze894I>dW<5M6RdHlWQzDt%U>D;h*9L}ai)f5L_<1V{JAyfOPgQanqs&5Ln7i6r zzpbja$c{~=4a6y7$rlo^{Ap;7F}7xA0S0hUedH6vN{I{iCx(I29@lYmtL!jmb%oId z^hUH~_6rPIzI<(uiP_*%FqMv~f75ct>S4N-B2yN1C%~wJ3s)FR=@tsQzeU|x7W)$X zLbNaL2Z54#iqj4~$y)l5l9UR7V6WVmC5X>H^5msoJU-g9CU+qass}|ie2;lel z_8tK$@4=6&1OlyoRHYICl*kwq2LVlp*PJzlvS@%N^G5c-CxaOlEUX(gzUj}>wWtCT$wnh8=pCuGyrO3q`K=LrxjWmZ6V zO@=U(5NHMi`IBduCub>y6^b~50apcplRUgxxqhfx((KkGN?V*IiC|MrXe0w(AY6n; zXx(RAN&&o}`yc=bf3XlIWFAZ)#-{i$s4cmj6!P%%oRgS&B!rS_7l^+mg9CK&*U$&j zfk+S)&P3vbQ1MAXxOj^oS&fhOPtz$oYLT867)$sKN~nSuG#S9qWsy_>L4lg}fD9Sq zEkH!`ASssU3PAAPog$rn+N?T35uydErR)O$Q-O~z2`}NB7R0E z?Ob8zU3WF}!lX*q)5qK)SPFa%GZ0aV9wTXo@!-((ZYChif@w?4Oq1AbrLvUR9=z|& z2_gxN2U4G$MS1XZzdND=K@5rlY-Zqvbiy(tGb%KD2CH^-AfX|}@R7DCePNp?6>@TG z$=9GwD4Dln3AzKU3tLYS?x+?OCMow2*lkJ6Tv6F$nq$@IKt5Umi2o_%{SVUK#2w1V z@B2PyAIr>n+GQO}NYN5@!Lqt)Hq$1UjwZs^*%UD8%MhlW^l&q<-D`H5cQjMi7 zsfH9~d(OVU-*a8paXr`l+|P5|{{RQ(m~p;8@AvCAb@Zy(6`#aRenh2MWg|E`t&>tbuKpUhU9SUTp(1A_-t7}sv#5ADV zUxZ{|=%=n%Of8nP7mwmx3!~z2Nf$Mrk+#M~g8iY6GC&Fke-667Z(Rh+_d0?UzHT<$ zY~PI?XKpm$ue<3HJeaZe!t|hDH{48UR%b5mo({*9-0*C;>GSsHfj>9%Eq83Og!T!S zny6kma=BEp>U!YY(vyEm{o+d9U2oE#DTeGTi@aQRrlBlaPBP+cnVefG!=yZ6UwPu0 z^5o0qsSV}nF!1TZpK_Mmt!$H9x%+PAow-$T`PSuzTZM0L75}-#maBlTpEveZl%A<5 zzg$t#P*M4|;_jacj<%As-0kyQZdV6N*hbv`)*tp;>}JEC+Y!IYxF(e`&4}3@mD9cf zU6)TemY}--DLvC!wyQ!w|D-#BkZ!jg!tXBf7bOGUVSQk zuPiQef<<_>aOc;)bs4`wxRvsXbhz=wJ+=Pe{j;DN328#&yt*tWs5qI+fg99SX1-NE zRYF(TLbo^wNeEnHqli?zsEyFP>q(>050bXX_$@J;?&3SYT8a zXbPLA0FCl(m1ZF|N58B;cBRILS%Z(OnYERA{v!P>1gOIL?Me7s0Qzj~i;EEN5Jx=D z*DlL;U-!djTmo!UTw;O3yjpcN+LH>q>ylnm%laN}B7 zVQ%_H>D$5Ybo)0#q4yh+Bi<*rG#N345e$av)6>Rl&1%cY1_OD&uYBTLF1~{X&T+vg zG9U#Y6)EsLD&WG#UYELEt}e#UJs_>OTkDFQJKf<|`@^q1@RTgDDj>G-abxq~BQ{C{ zLX`qFC_XBHkLF0#-EMe-%u?^Wq6=yxt+Ehu9Hb{pKal2i}@}d$xE0jiMzj*=uRgu>2-|w-`G2(8G6XW}}Tb(baEa_fiX^17MJGw; z;eZYH_EDlCh02OEk_Vj_URc*QgSkhdah_Ucbx2D}jr>+0IEP{*^!9K%TLLexOIqfL zoF{?z$v~_ErYr%vRal{91|8H0)Nn{dP)(%}+G;rQx=oFbyt&S1;JATeOAjbMDcZp5 zxmoF9U0D%*!{SUE48;<8Ee`mr;c5jUPiWT;a4{adUbJPMs@T(CA)8N(qUq6GpHeV% z`S{gAaD@&|aKTn~&q?xu(Tz{J`^cXlV3NFjPlA;NPZ%}3#evdMBO0d?*GSI6I0kW7 zNd7-kwqn=fG>)kj-RQybk-WPmZF_-koEQ!jM@euf%})z zp{uzuP*A@YL%lk%x_=YY#}Iu&^~+#dc`&SQszEPFZf}NzA67y=1IBed>&x0OG#c0S zg!JX;z%RDzjR;5+o$m7V3e65k6UkKahjey8h4&%dfi7g#a~a>`ZaMvi16YuRoM3Q0 zf6I$>6ug`0lxga!416Ac0!owwidn*_5#bEF_UD)0U~t=FidgI(Xy)2Z+#RguKlzuU z(>;67chOF{DE{mCwijg%iKM(PZ#or!a|k!`fWpbD>E3vM<+y^1-=5ozMyfcSwVAjN zWJ1u5cqr2G>WO}>JGXD#F+c|6>b9M!+5#mHSHHg9kLvH*>Mw2!bv3aZ8yQ)z+ zm=AXVdoo&w45+X`H?#Hh$PeAaFXPTt+$@4l(C)()k=b9!I0%o{3t*ghJKScfx!fgN zrRqIqyWWDk>ZF@qo*%{r8@CRN^x{^>_@(=?0NAPfQ^n={>Vy~Z{ zQVV|fV^sHKNDYGtBZ1(el*ZIV!K72Ad_HX1qlqH0?)?4o5MZ(<1)N~u9b^DUD%y+o z5tG#cE*vc?I+}msJ-P%bX$QUUfy_c2=sYAONL&&m?tT0z`!2NU#4T~ds|et;P;)YB z7I}RTRhrPDuOfmJ`zTV?=0uxN=7PsmJF~D} za8Hfh8%ZBNZ6WoT^7(Y|H;+$#4@iA7uJtI_7P&P&@GDnx+rb~$;2*rQA7h>nmnMCi zv+emXgfnLe0SPA=Gdp}m5_r>EK@y<`>*?o66&hn;d&CRx-oGW8C*OjSE z)>vsCkIlXk^)X~kLASAT!`4NG;EsrrebFPDx#7YC`VP74smgKB5v-wzDxn8ApdU?e zWdU;s<9j6xD&{o+IofwNOWu!x!fvALPC+Z~(1WYeN8h7&`8S00FWo}Q@c5)@C7_7> zF(p<4dqm8K^#s?CJ`c%UBzg4_WcJZ5W7k@svL_CVmEE)Y>Q0Ce5!bgY$=$DM&goPr zokPfFO$L+V5r%iI6S~xMFtB4t_iysaEPX4Q$QWDN+c*MRod}Hn>X#1O^uSJ zC|DYLiED2_-*wxOz22!fdh$HmfZ0ZUoUm@|Sibg_6Cc_x?VfNhHb3{Fav*_J2W-c; zy!kwB_x!4{=Cq@=tx&6jUx7jUy~zIO1UcoX%b3|#$T*=cwbE^?eNeF74hxJP~4uV@Mc8bj8Dlj9|}@zHqb@QUrdLj z;8=F2oSLlq{2T34o=*}_+;_4|>CFcLMgHmvnc45;3dk zQn$$?o4HqeMcB#Tl>Q(dy#8kLt&AN*cA#Xhx^*=z;i5li11fp6=+^=;oS#9g}*E9zhEYNvc&-)*Pn&FTT2^Je(nyFL!uDUX=E z*LQcdTmR5~w~OsI4-ZfOhaR2>&u`na_vp=sd%RDzZ}Z$A@#&%G!B~uemv7Sg8ZW<0 zTZ6s+`TjL~k6t}*urHwOX3f6i_u37-Pt=+VVNX8682SWvuCMhu-DhjKKkW5Oo_F}i z^M(haCT`XqIQzZb@Zh=p(1?BKeqoFT)Rt9_UA0B+7^3Qn9~tV`XX=!V9L@RiG6C3> zxA-9$1#$brVSU_~|JHI5hQ*V3yYX{<0s5cf?TwCIjrAzK^elG!Ec-~&lbJ+Pegsy| z!G?)#P-K=ls%uy$7cU%B2QATA)6nh4lgh7!w2zME_(YgrL0M^esMnco>%4gsH*1Y`A_WJ=KV$S>{hO4CdtaCg32&W?o?~k;Dr*5x^gJ9eQUArBxv|kR@{#;TI9!K(l#_DUQ?8d_%PXNZgM_zZtrzK zl*|6YM`V5veHOna;S2ePm<;~Bo3NmDKno2e3CjZVzo|(kL$I?RCfQ$yxDr$nAS0>< ztlt z<$GPK!dMo*+Oj3u&Fji9vweR*gE@9> zmI&lz!BYSLyoA~4&|@v2fXYOL`sK8w*sZPRCsCy(RN%_3@^3vHkPCnafh9;Bh~F^J z#?jUQ>-A$afGF@&+A^4=nPJ=uKzd;#50dBuzd=QKekV<{2Cz9!y5(^q9(<(yCNcoP zTEiLErPV)nJ3{1g7-f!SbU|}w>?12QD!J901ITF85F*ahRsz6h`c3*NeH6Q3BqHZ< z_;cU&=}9{+(p$7}eW&?ex;0*upBWqd;)bf?Es|YIvKw==Ji@D-zF4)xo+2q6?`rLq za~Z2yxfz(2&7%Gm>jABp1;&KKJAc%6>=fk-o$RtiwrRh@4YILFK^b}^e|zDfm$rk} zdBz!97C9kdzzJ47lE^_yl+)120!v{mH{+c8d?^ZZ!`n3!e>lLy#(vyx&2>zG1{_tD z_1EKQnBy734j!>5JSy=I-)?B!qKC-8_)#Bz6-z=4c|^G#_(r=&EqY6}8`7mR{OxY^ zvVM7s-eFg`Dk0IOrrhj4A{s~rjxSp)t7dC^Bt^X=1xnS;Bv--!T86~%b)_yT3eJSg z_&7_ZTHLsE;#RkLJ@a1uG@dJ2cFfihU;qH4d3$+*6?$9@`P@7?df`e_+uaBca+TxRZ1U2XQP%o|Hg$tI zJf-XaG4o_uGW#8lOhGUOkw{5k?t_M4EPgSv>+EhkD=sBEu2pBWV%uGhk_(cx*6DYG zj_#6IPsI9rzZp9LkA9}c^Db5jF}tr}y!RwW9xTcIBy@<~Y3jQik3u ze^~3ptz+|*FO(b-n6~EvH8AM^tQ7yhUMFY%m)A*))@K{q;Ok_UOQLuMYTb+fd-wT3 z(;2Y%7ZdiM-KSz#-{H2KRAuK>hkux`Vy}AsxlY1#3-f1waHSZ&PVV10ul&z-vS?S> z5YQm!F$!NNPkp=;gA!2^{T1KohjgrWs(D`}MP+jsJ)bI4*M z&bHY3%92|mq(;8tLC;}JL)P&xm)u&d81|PYU)Og zuhhnZ`-L~Pp$9bw_9jrgXu(iLbN2Z08qCkSqm~XfRmXjH(9^CfV}9#Rc*94-bkiFI z?TxZKgJj#ndhf0ix_#~bjuf9khVR{@FO=Gz8JxWs^4#wUnupHSW%^ycihU`P-;N4X zStr)Sw!W-+WLvtcQ5LmOS;B@P?hJgW_=%AzKXDr4ACri(^THh0*SY^=)>zXh9?iSA zw~Vf@zps&s(y+8V^jX;GR5T(_ya-KAId8W{uTG#$X5XS{d~e@iWmBg@tv@Q&ToM1< zq|U&y5zR`ptmul*Hx7vG|3!I=U(=r`Irg;w8&|sA^yiJE?V4AwO23&iBbAKm-CLfQX@1aWF?jUe%CF(=hxae=lQyp|j_03> zNw`~lZ}rbi?f3tW05LAsMDRZW#PU+mO8*HEE11O!_h}|eRZMNso#E{{)Wxz^IFzXG zlcgdWY`r_{u-FTJQqfw75nEC2kl1MsVrLLF$&(ZBZi8kKKoz__2LK{AB*W$wfbD)b z4Fxbzy|bArJF2$tmTXgZ7sLhG_>o=|?9eY&xey%LDt9_zOdknl7(UJ-ot?RE_?Zuc z=gy|D?Hp5g1X`HOV_7+zX5mt+EW1^dxCr^iIiP1u z_3EhTu^8+b=lHoXG@`B*khXMUdfi8gv8_d5GmW%ltMZHSPP?ezE?Lud1)mGGw!?T` z8CgCN!?iT7^d$t*;%|M_>HwVC*lmwW&;Y5KIwdr4@Xx#jWxa;U%cx8WKoMO}@1el1 zoxl6m9`|_h0)C=!0w0#Oes*r1dUBd)<)0XZy05e>IU5^KZ-2kQ}n^v`ff|9A= zV+}?5n6+{{lclFGSaAK=VEKmEy@*WB%T@r!z8SVvcx-b=h*}iH!6%@!*tNF!%V)n% z9ktxm?pyrh%>7HSN=FZgu%Vqqu$dCMw|zAE2sBW~I5a8-WQI$z8_&6T^=*(JxbJse z)1L8WzAfRCNwbjaP&}ggPo|g0#Fe72$HPY+>@UgwrSx^kF7iDe{pO*8u!}5LeKGjL zS@+isv+duaU!%O@h8NgNpR7Q+D@@^hK0!;CVt^z$#TjS3G!VdxommhO1)d@H zYywQp*vQD2Uo7Z9e4!_0%{blQNL<`Y*HAUNPf!9dDquiEYWJ`)n~(mkpvhk^drY+W zY(D2ZirzE`$E`SxL*Z1h;}ilCAb#YI-Bn zp4;ntjwf){NmckG)>fpR4%mdOC+whmNNo4-HZ6;hR;G`<#1=2Ov>h}fh!huhaQ|Xw zq63JrvW7ol`v?-VNhay)AcAFU>@4wpXDe0py@owkXfEl{e4}~3aRNosSv*EL+KLz( znV_mWi*;Sr?gt3Jw0mbSD4!ou^6V1btQ4|AI$?bMnoIpN&)&J9b86~pr|RSQIzL24 z8$TQM)%OIK|ET9Zf|;-lyd>xOYw|0T_AU(r`MvX{rYlp_%!a`-=bshcE7M+m4X0{MI2K!u z9!BYrA072!FHV`?+?4T`Zm~IBiIF%LU-D^CDD!t+^eMBe-yi)~x`pSHcW;JJpDL9_ zPR@*gt{n$->WnkYD}9&VUBO&hsQbD-2w)rvda-b{N?lX~N<@hIjoqBGdt+E71UsIj zNpyd|R(Pm9*@&xLsPZf`bz> z;>xc=fl+jKR|r!TAMKH)8HL0w)y4=>iNArP&kiG^d1xxb3|}BAT+R@!`zt>;D39v)w(!*W-bU>PcE4NDUwR5^el97!}i=K@6!7!iCO}**`&hd%osUq(})iDs# zqRzC*FRX(nJ@-ff6AWuK(sJbLQ?>vm0XLj{q6{UKnoxt3pY97YbH;s*lO|cd1`cUUvx@r{j~f@r)Zj4-(3PrNKNS zyBAw3Nd*V1HhS>Ur&!49cJTMS{p=cNC--9N?Wy>Nu`nkpnhMawNr+%zD~*+p9zj_$ z3`B*ps#-BBG+;;oej*b_)`4TM_s1@RnJKvVEhz_N{@%DrB%~aKFa)q<2~3Wk$P@#v zd1G8jIFOF8;{q4}VZ?SSn?1V7zKjpd=j{%U9zcqlAe04YLkcRGyCsW5=mmtwAwYYb z^g(+J++7!^0XjU?{fmg-hrwGhJF#ym*&@uOOiqcvNeR$|VI!XxgdUdRjC4_mI9qz-x_>i=>F;GTi%n1m8 zhKtQ+Io>2=V@6pUpO#Yp8S%;+fF;s|@D19#r$e>5l2UOSTxmFc0dg0#4Nlt+z<*K_ z$mimnIk~>RX?ywTKnkiT@Z!VpLMrF{oSsnXP74pN=2pga*pJPC@L!+d-_b> z4$8lzfr};<-mJSrObk8^qibw(yyT9K7v^7O`0%G?ds)Rh`bDzW8e~+-@O;(c?NmwD z8?Br-8;R@gdjVx)q`wy_Cw^(`WyyNT;9Qk#5WpFIV62}eT{pn=;bYdburvUp>@DTH zOGe{TNIyR7uIeqobN)re{uBM-6ag&b^R1vLWCQ8Omstxk)2tBM5#x z{Aah?b0u)Mx(=(Nhl#5Tn7!n{N1>`NgdpmfA~Jm(lHV5@58$D2iY~nbUyZL1)WdYW zsYmP8W@qOj=vN}ESnnvJ2uKLyisw^>4s)e1a>!?Aw^)rew45e5&dJg_`lx>NoLo$x zF9z96Kn9DP9>KKiGIM3zXU<|=Il9;q{4r|NfwhrG2&#TO*|>3|+rH}!Rkxvd8YWOg z+JdacPqRA4#f|WU_-6^zEiw^j^UjK0`r%E23mSKT%?K{K>x#@nSe2o#LZRmcctTuFwDs+rj99dGhAcrYcBVBK;yXKl;OUbJ|D?Rkbgu>ny z9sDo=S4NmM@usgod0Se3qqOCwfOpJh`q?)7!ZwHK2-yd1&YP49AmAfE!o{b3&y1?l zCs)r$?LNcp2bSAu3LS^cIu84E9Et8YR@f2vsNz?;oK-K}qX$x)06giNynD|(1m%tHG{WUec8Uyrsy07Bj2-8F^Xb&t9mg1XZL zJMtuZ7-vH3RAldO>h`a}8?d{C^bn%(UIE@NkdYgy&tE-4YEyA@{-H&pGM$^cJ=zdx z3Nq0ZO4LJ6rbDWn-kD{D5+9)e^eK>#C;?(Zzhg&k-=FlLb)-n4X5yG2s%1tRrHEDK zJm0_kysC1?IzW4xvFk?lu2Mb%uFw?Fqmc*@$|k&o=< zXt4Z^x=-1~Jnf&6Yqk#ng&4n@Mk*aYvv0DxnQ zTw?<#0IUN8bCL>}LcqZzG+n}=zkCPny?6DAr+>&!6958MX?yWe=A4hq<`{E6>a9Fx z3kE2l?s}>-a6qTyOjBRfc*qT<$jf2idz&{0b>7Vu zwKvWaPLlu?J{G#gcsYuu!Ut_SkV4rJbmBEW#`)q(&G+|w^Nc}xf6qWpoICA4O`gW2 zX8aH+JTvd;TN%Hq@V@%opvz@&h39{ggSqo^pR6+q$qH7?v-onN?<=9hTnU(c|03o& zX!|){iv`e$6L6iX%L}yc7&m@AhB~}U=sy3?uvNeX`IxWZ<_??=0Jk$>yEO+1QGtvV zq_xybi=qix_h+bqu>l>2z!-3aGO5UqgJ_>tSfDT69ZN_3W_@Vg`Q}Va(ov;JX8Y7C zBRv=Z(l}{{C9xL{00kF6L=p$Povd1ym8h%ZZYKwWpMo(fpzWS7k7$|q+^46*P#M@G zhlRo=!NgL5SsJoJ4w+jQ+$N=0B zyU%etT#ZFi;2IjXY|r-@$__IY-(2%}VbxbRf&GPf`(Jdph*aypSJ0yHwk3$?KRE3( zG{%C<5FBKNB#>@{OqT?-S#z3w_8P1?ZR#95p?Ay8%}5Oj@JnIF#b<_hr$?57K*CYC z9zv2lk02veKXA*>t{>$av%Uat} z^e-+iysIeMReSe+<9~8_;pEcsuSh#tV&j3Hx~hM}5bEJw1x&1ilgod06>xI-&#vOH zNW0-7Y_o!42u_WEZC0nhe0bjY*Jc$jqU`)Ho7Jg1ZnpKOoA%ZOMZxNWpI?X%XdfRN zq=m;(k+N$NT1lC($D7A$>}*3-h~qdZ?<-u2{VG zc~Rr##TPx4?V^&7Oi4Kp8%ws0*GQuM%~@NZa#)orNrtGSZz{Ala4JMz{w5}_sTq|a@;W`~p7q}MKaX42PA{n?|fSGDy5 z*R+q@1yRKbnOK9Hqtv#tDwP~Hvz_YSa;i)icLp@6VaDQat*;!DW*^gL~o z4w&b(63x+kw5*T53?+2p+ROvX{BNQip-z<9Q&R3!vG<|oYcoHdqMYoGNDZuCIn`!l zIjZj~BYrW|&E}-euOa!>UBBKOE4%aSt!k7WOCqRKXJI&W;hn;RFxY10I6_-%pZah! z?nO!>!}NVb!bhnOV#BFRGp)L)^&gC$JV6UotQ`t3{vJ>Aoo)Y!)9d|xfdZ&d#S&g% z{!CWZe*5!<)2X{OQ~mnn($~6)yG!35E&NAvDRXLhw(CFD2X>oR<_A4bt^6GNC%KIH zzVaW*fmf`fSKPQf9j zRKhL<29Y8H!23=yh8F+;smZqRy{&ospjb<7I$d0X-)wYEj}?F>$-R>8G+Jx$B`Arv zCG`tREKBt=Tr#XN+6BIZ_aWB!9$#hb?@ps>2qi7*w^KYzQq)lZhC5d2$iT@ZiGz(% zCj$#qIO(!v!23L)y};Luj{w7$TjhKiN!y1kEt&Y87dDa92z_;V`gel~Tib9J-)3Pu z02hdWId-f4nP-Rnl$Vk_w;x6T3h*`Rh%woCZs#UTS?5M( zC@x=D%0~N}t_EYJry0urn+^kertCahw&WeT6%YGpvq!yP&j;T@|XP#TCIr~zkL_L4+ z37>B*)}o^%%Gsp=wOPnH6$RW~%#2zSO}JEaPUD#M@#M&Xkc&S`O3f8Fn#85M6ZBya z;Bc4HIrY$j-q5L&RdenG)A7aSVb;=t05Xog4Rgw#t8x31ava~F;l)dbu${a5&d8F` zejX*1@YJV>O(XfuZKK*H-GlRPGR2t+I%hXb9gq~YLgIMG^q-9|{}ihLJN+}G@}Fh) z{mIw9=8+Wk?ySq3SH8+?{7#D?>c^$I2UjP)em{RZdxWq%q|OE4>MfTLqXhA7XUWK>Ok;si&zCX9^pPbo2ZUJLRIFZOA z<%z{4yeKK@A&!gRlYimE%`vQ`BwP06a;K)SAYPwWKDBd~nN$TIZN^{#-Gr^%VF{~Y zmwm`qPqWkI{6t8W50mAR%%=M@B@!rvCFK3lC!a6A+^8c$J;of%DNHpV_M2bh#UqBv ziW=^SpG^i=_V|2P)C&Cobn=r7x|)Ue3s6c!MgSh}(QkuK@$0$PGZ)1G#P5i(y|cY* zSMRg*wJ6QAXdv3u=9JLBWF_VMS`;LO7l)*90exz`c-{Av(v!M`Yb4==meJ!8(F_?^ zIDq@cCdAN07r5XMgw^IEW7!}Ju5U1~T`c0tYxe^Jm2VUxa>O7{4XTupLVIB*79w$7 zAYuUS?GmafgqM6GDUSiyY1deIqyWw1#-)cc5pc1WL&##G5p04%3mQ&zUUTtR{G>i) z>F++q=vjZLcpO|25Ucn&KEr(m0)r>4ps}*RL$pJA9hjX97hQ>2Y?04o$1ySjTa>y$s@00m_{u+yNy$S4r4el5{UgKc;+-_RZ96{hbRe@Hd?hLnXZBCyy{U z5ZbX7Y~lyH$XN&&pb%R)BGnvHSRL*mo%n;K>N0Z1o60DTU|g*R&B{RbIJj>S{M!@e z0uN;|e^isw_0>$&MBj1=!*t1%sAYRZ4*Ar zEJn{u;^-%=1#{cxi@F(9!tmPP92uSGhN;C1^C`q(s!#wAZP6n6rz;an7A@8CW$XKL z*B{#W6Z}X?s~JLjv(6kHSM&t1dl?D07+HEP7(X}63A)HbI?e&W8Z)DI=*4Ue$wmuo zL(~sFGB|u2?XYzo{KQW#x5F$==2eXg714#u0O2w&4#Cait3Vli(IHqogDTqUt?)qy|az&OJ+VFr%ILq8u;)PHKfK3jxK6>SGZJ9+qH9E{2J ztrzKM=jg;KD#4vwU{?|eZNQNjKr8Q(*$$R@Ug{djAww4NNJee+HMJ)TW3MWd&Bf<& z@%shXv^7K33wuT2zV0=aa2|WBy=8WL8CK6g2xfhBxw}}Dfyw7nOQ-A}c%^A;X)vGK zJ5$i^R8>W`9*wSE6@u&Fh~SWD2R_@O|LBXa{Qwn*QFgGbF2h{*R z3JZw-qJsH>7prPB@rZ3s7ctIMjQZ}106ylHDkL67IL~A4$tv=*!oYoAQ7ANDE~m-i zLR0w706M1Eq~bh@@Q{PEXI^&-zT-~atIP9WX50!^z1xJv9^~X9o5={iN?M9KM_B5$ zFy;gfAvRCY`>oh=#`mqIsNrHSnk+u(2lSUCqgj3eU5!r@C)N%Bo~7hNSI-_8QklzpIT|s%6O6F-_|dyz3Ir z)+Jx5OKq%6e^+;5sg5OIpKV$XFDmlR))!oc#>kKGz%()Q*hS z(&QT|-!9@RfyZF(FxC^o}tY`D_+l@TQ2*~q;Tpg0@ab~c}gdsKZKpCrJk z(-AT(NP-V-BsUFuH*FLMTP@JLyeYD|@J6Ufb&Z6?l)%vdQm7fB1OZBn$CHhZzbzpE zhFfwCUB>;%uQbbZbl?HW5*JJy<3VkE9>FuCIr-ps$0;eSCquW1(Kq(4Qo+*zeBedA zqV5nt;4B2Jl8CXk_EvMvR?HxX;dZlzj!S=nV>F!%+n?R?cT|RgkU!ZlEd)f4*cDKa z+4o!YG$D%xP^~AF5W&S)ayPVtt?oG4A#9KV_?7L3AUnFjum+a$jG(kU`836c3q`aD z6}G$x1@~zkh@b(0z!K)ym#!nNQV^n$b=M&A7b{inQM=VJec|krgOx4(d9a@Z7_xjG z@WA4fX4>aY_#pOaO&xg;I)PxMhAFhIucRLcYTLREgvVzn0a}FxkoG)6Foet_@11f) z4gp?2W?Qp^xbMDmh*8DiVapw*zB&a=HyK*ubL`UmK4=OY=FFijTYOw(uG-0VUIR7oO5xn9d_)E-W0 zlM>*LbV^xfjH;9_I{vkHUc4o6c4;V94WjhWWtv z6;V>_SMpAmb--v)=cn`+U0|1?lH%c=zBH(3fTcg1{%o{`3X2KLa(wMTPmYpO^Q04dU@Dm1$}}H*wJq6 za6m|tut?s~>^rXv-oM6sJ~e6bt+5?)q3wRf0rkdhxSI@a{Uy-^X+gr5KAgSok&1Pn(Z z!GpWk%Z#f}R{Fq&*D`HA6P(5wiZz@{qDX)Oo%oAO6tIb^?A<7mNa?YUkK_Tt`~HHW zCy%ICJC3I!ODGk&lv|SA_FdeF9{PcqCOHUzRqPt1QPN2yJXFAljj9}Yyy?T}CZ#9x zkLj&NJt+WQoq>>KjY&d4f8!WhtVt+tl&U{&ZP7I3{pv_lQ%koPvge6}=0}-%G5q7k zXY-8?x}Wf?+y5&kn zaZ?q}v#xruhu?SS-^hezxcEnLWG9BsIf;$G>QuM|z-Fwts=fcNyiI9akKdgv?Yz)+ zY91|2JNh8thEK9l`>dfe!zhF!`Y5{Lmvd8jlTX}CyNHag*Wq_ccXPrAbn-44-C`Eh zoi6q%-gQ-1fP)PT|8o=X<5mZT_RLuKRhK7^SC$sDm}%qWH7ku(Oq~SOAUasczz$!R*)MSSAGv3tnub1O5-~?5~dX6`z$uy8ug*YLo1!zy+6*!%;sn4AZe(*v@Vt z$2BfR(=v?SAC{ZC{yz5w(ex`EV5sKg?$g%DVOIoJR35r-uUL5*&a*1+I!kc3*S%HK z_GE4f!J_f#zn&>XL;*f_92=N2IH?5^_buw7y!z#}@EWHPKv5Y$PXwUO6T;pFHRA2GT z^44@binf$#GSemjnodtjWSA^+)aJU>Zc6~0k&@Bm7WWO6&eebZ5^pg2e4>qrr9KCFJwY0aq=Eh7WI?paEWsNXbI@tGW56Mry?k zHR##I!a#_-)`!HyfVk5fa_}--xL<_3EHs2DwQHBcZ3v?^(+sFhzBXHRwNXoSO?Py? z#ul&bSPucB$!Kdi=}U~vkYyim5I}p>#}<|Vj`UVhQ5plu+JdlW zBbw){9=4s+i<@p$r|Lg_`gnFM=b*hcLY9k?7tk=sNGrT36~uk;Q@%2YLuP92x_&H# zbgnV!>wP?MK%l1lJGlcWW*|}3YRaG0lGjTO^{{zvmk{NhIwA~HiDhf034SM;Y1|V& zKgM8)4^j&DuJ!J{OWjvKW@mn5FT+$RPI-=%Wbt`j(#b^aLe#pWo0jS&o))z#10L`D zdI5%nD1ej6!ELAhGDZ1>9{(eWH>K@#J-vFGl$3_s4plLPNVFi;oFO!c14tC~D|Ja~ z?(+U4QESOnT5EV|J}3r;jgL`(nIug_<`4Qp>4i3TCLbDb5qHCX-ahb&;Z-lUr|Lo& z>hSv8*eyU@c+Mn z;&?^k_1fECHFwW{CDZcU-j252=MwJHlXm%xPUqD=e!nv~zk7IO+5ouebk|ut3*W7w z3M9!UhgFFTe=&G{ADwbHv>nNtO}zPNZVH>vJO1HU!$OlF<6iW{u8)7-E<9d*elKRB z`{U}Lg(m=!!@xPhJA=i)Z3L!F4&MS&}gemMc~7v*)%&LGFuid2bsxg zGQ}U22o*XXHQysTeJFxTkfL!7C}JsL_*`WpDwmWiKphsGJd$EsNU1I=)jotZMnK#4 z_Z*rb4xAad*pXyd6P$XuZcG_RP3+W<*`DPzM$;Q8&m!Jbm>$mqd6mO0#A=P%Y4%wj!ZdM_taUHPb_{w>A?F+BZ--GA@RA?wA%@ z++nT}Wn{VXUTLK~(I9j-EjE2sxu3+4q+>!U!3vJ--WFcwg|6;aMPeYA8BBAM8pF5o z^NnktH8s~${2P;F^OH=4UDMKTQbtM#%B9M#5XG3WfNJmGibV~ajM$>6xaSFeD$tnh~ja? zNRpdnM3-jZcf+vvz>yye$D4*)Nn;T!Y~m`JfTp9*pWay8c}}U8slSNnakW)7j3>*| zJzV3EofxJ3h!4P#)F07E6|JNkqgOHnxT^M&MQq(;wW4v7#t5fNo19%d(irqD4K0D7CGox4^@s(O^jWcXgK z4oB*3y4Vd!DD?mH4(DgwY^4y61RAOC- z0%5Qkt~Jjgq{xjgM8mA-!@ z>S-s&g$A590FUIR!p~|gvr1d{W+52)mpa4kYcZc{84YD;_r}Gaj#~H88YRRxd|Fpf z7pKWevd`JO?xG#$*aU+nIAL&1>I*K=AqfMwxCG-DP6e#HHkW+YD{8Mmey5%M(_4j~ zN<+ONgwz^sM^ZsDoE&u|X*qCYo%(B zOEtzywTvhfZs~5LGTlREdeLPD*UF3@mzj)}nQfGjq{=Og%B}zLgxFsz-}|`Saje{V zqns>td%w|bw?nr*qHlX$yM5?io{+~!I!>VF>h>!t>=v={>(2`%WV=b^A8t!JbQzDl zqK%iJ;N?j|>h!zORj`C6f1It)+jtm2z(*YNge^kA2ty9cFL-qPm9YvL4kTO6LyqlH zVC`4quBk_dz=epgHr!|YNxTs8*KU3kpm}kQLc{RsQ6cke;v(~mx|pB_4V2*QpJSfk zGPE~{{z7lDEUB7Z%NP{-g#Q?&daP=J<_aRLi@>=J5hy@EynBy|PzUrpQFl)AgpdM1 zoKhp6Un4LO0ar8?PjOB^g;xg@J2KJ<=Q7{1l zuwaM=qxjdgAC2np%J+Ob^kFBAn?;aN-sG+=A_)XrREPkSs8`;jqfvc7z{uxXG~}g} z{!aiGN(6!#A-MqGe&eQl?WU(W@WO6@kB&o@Tl_kX$M?P4r0LKBbTNSA0)aFrf+o00+wZ^J#BQP7G``no#Jafr^ay3I z1_k;}9@s}Dy?d^2G1D})uTiAye&3;ebB%BW$*Gl%8+pz@u1n%kT?AC04#c#yoo{q{ zP`i5^_wKT>8dZByk$C_e)cRf(hal5%*Rp0^c%Oer0nWWY3iUuS= z1&%5>d`-av9}WSLB0#+Nop7HPH4VQPRgfE}cfo?O^Ay{gMu%iVkGER6w~}ivX4E9A zS11$kiWI0KyBEUjy%z{gGlIevd++<;n@phcB&Y-cotL_P3QiS zPfD*yu9a}x(Q7Tui&IA$8hiItdxn|>pe-M%(xv~l1QV<=8V4H#x|yy#%L9)ekebGZ zz;#F>f1YX5C-3^9gexnFj(6%m4)CJ$m7S~yp9_ka;8CJvN}LT~F3^}RRFClUy#%g9 zjs>|_ELx*vsCe*MiY9bb`U#^WD@o-};UPaID#HT4QzIBA7=AUbOZAJvlmqacQ}zkW zCXh)os*XfUe#l60JAdd*Nw@lHA?&h5UPgj1-RtD&TXCQAU>nTgX2^4_-UKHlH(U}n zU>JlK0(L@O?|v>0Q)^0+g1!Rnn1`7{sj?82-2>*8OrcI($S}ALsktz0Ef&t^whNz& z6|yJz`oswYW;4ZE;v&1%s!j{`BRUW2^x?ZDj^KrRBs@iV@=lsDDm&;gC7D&hx3cw0^2ks-Uemch@&5fEi`a?-EAu4&bHK& zTAGqLk02{j-&>BFDi%6%htK?YviAS7fz9mTm}u06Plg#Sc6Og%qFk=z1A{&xXtF2vegPgT;r~aX!=N3&2qoV>iqHm38lHhww5>xBGWr-S6(~n zFRToa?KFSBaq~R;^R1VE?ayJKh=rf;C@COobG+c}zge5WhYJtx{bDMBtj)VunMRNv zVV1$>2ybC^;vB56-yu;VC~^`akkFBqqMsSb`Ta-dl}u=j#iP%8M{Y)aKF=XSzFhOp zT%QSj<9FMX{$q1M9gyK{e7i3~0_N{2uz~r8Dd$b#Z$M*Q`K@IG`k5J;Y1C64+RxxU z4~<>=YMr&U{K7@7KF`QR_HQRw#KNbfNpa8nV{Ec50vP%;jwRjHQZr|4YJ3(UY+lN2j-#+7& ze3wnAj{|OU;Sg@A>|ArV*@_?T`EdZK=b&JMmSzH9&LwP#+(NBFvM$M30jl@}fG0rC zyf^_4kF4Fm@v~YE7AJ1sBsl_+k!=E{*c9#@$NYO-R`iwv9!O1q%Mdf7SqicNeSH!T zE*xY!@FU++%u6L{QYXomyx;}m3xhTnHT?eSqH&)h%-WwYfFPD70tv)9ND9fB)lUg7 zOKNG#4qm2YbikC!0=@zrxvku3q5vMchYGfDck^oq3 z16_K++ET%@);OtR7F?e}gRG8}9#iCd>1A{#YYmt*_af2^B1;f^dhY1?lM}=vJ=ZPi*Uqzmr?8Dr$if=q zcKAvArCENG@D2yF{F7~hRx>oOP7G9&O#wPax=q|hhKx!Zirj05v`e-5P?6O1O@f-a zS9+4JH3<-*ktlYOULCb)zd9|N>y;IwQ38apD-^c0Gh?~nSS2aW zZ?kSVUL(IQOsY-&WE`!DSo-0{_o_brnWtc*nJ>PYK77)h zP|z3%fxbw%)MF*P*;5-ZKAEL(?N@D^SP*^90#kz|$+=F??d9jfExucAZx&+-V!qjY zyXYymVNe^M(1^S$x+=3!adV7hr9lk`6aZ%^ZjW|=f?2Eo9D~Vyt;K@Q)=+>2i^Ol%ioTouD|VYcB#8`Vg7gn z>K!}(d{uYr8UMRG$40tB8)|FkPuz+gpXkqg`0U1M*A#E#DZM?-16PUzTcn5Hi0idv zO??l%AM>HpVfF5hE9WL=q~CnLbN<p$S`VVlK+#wZ{u}tS%Ea{8a<2{W& zeYw;8O!H~L;WNb?8J945By={*_*=U2e`jsBltwQY<{#BszBaz~<(M(NKcav6=H}M_ ziI!ki%fwgb)yLz%zef)I?`&Y36QfeDE+LDWj|OY3yYr9B<``>z&a#hwjpAI&1xWJZ z_T-P2f2h!d&w(!_n%P#F+;94pa`?dJ`vdV}O1hoq$Af`!3B|gUUF}v^2V#{(CsC(K zZGf)@>y#zuUdF@xUrhr^Y9t6w39Z6&0|$^`G6~Dcs~(R7>uZ&pWGHKi!~w0Y&c{MBPfP_Oyh?z;_v_^F%%xfBsrhdG7HdB zTS{pDl+X>m^d`dV3xKJkV5dU`1euWA4G=*RK;z=LoM`1jt%cGg(cAJnn>Ft)#qYjq z4b~3EIVg~wfj1(-ms)2S*n04Jnv$dxNmh$YIn*QP(|pmL5NF#=vVV?yB!PWE5@d7D zSFFryU2_K_dN{7kxp|y*ivO z#fubPSILgF$@W^w$Vtu4P0jA~%idn8uNp=tY_kcmHtUScn1$_cch8)$yd2>r!<@OW zD-~Bf;(R*zim44bVG3vbg6yE1S7(4fbxMYK5aC1hAg20OgbEKE1USy(OcS$IRP!p% zYe__@Upgf-XpaC{3xJATrI~)RKTP0rcpoZ^ugr4(lJ)yt&d2ur-w!q2xcM+bESD%a zN)=uv_;Z?YA#bey;ERlv-2F!jB-XE)Maq~pXXEWr1S(($zFDUM3cyK$+w^8Tv*X*c z-`MzjI20XDmFads;Cm2V#{nfG+zMn|K<_LyX_K3#bSlH;%{7JO;xmSq)p!9SJ|S** z%8@~MD2{CA`o`p;r`KC@`k~G&LFDy5$*YPAh3jde!}4N7!LF_>HzbSS+dAjrPAHO% z?4@CAhcAtl7DbL|Z9;M(QYa(|vs+i?H`yx)eC-X+=CB!JN@BRj*>#V^){C;AyQYDa zI`Hkssh{S*X^ap6c{@ZYDLnIwS5ZObb|xBZsz7$Iu@4$ckTkamaMPzQr#>~0S%FNl zVf>^qV(^S}Bzz&4ul7rVyfQJfj_LGS+2T6iU^zx>`GWSur$PuvX z2L%|QtCw+*paB6&U;Ii{zg8+Pe8ruMRHDGkOD^Qzy(r8}7rC>d3L)*f`c6GQJ?g)3 zm{!T(W}?cZ00^`yHu^strc%}QM%9gnsvksGH(#rM{J6SxtorFjHJDAb8`V5NRMQn* z({rt+_i;_%SWW-G9HvIKZw}QCN7s&As~t1K=RG*KeNjIoAtc!I6j-&Ab2b0e8~#2T zoy>qjwV~(|=y!~eI{E&u==-;57X$20B{NQ<0SJVW;i!j~0kY-kc!V^wtC=ZFW`boZ zfC@KR3ulI-FVleaXftF9_A?-qXl0+M0~LOWrFP#>rqkTSg-Ul;CFhxFyE0uuv`TW;;}%A+Sk4@s-6q+cx@$OXJ-B~ z_gwdV@ymefc;56f-=jtpf(u>6mu@`7!Q4<#0yMINbXEz^h-gy0-elR*bXYp;ugsa~ z4JBcCMBIbhbRG$c00226X^k90-Nc3PM~LlfT%=lqQ%ndFOrKq(lIZ(SfeQDL4C;_A zC5V_42Jxvv4@vtTUOwqh=eLB=1Ytx480Tt=4*y)z-bvE?gp7y(fN@b!Ody-dVtkbx*EL?j(dL-`;qtpBN|%5UMRJp9v7#!pkJb-8~- zBnOax*-7vwkSI@9_HoZZLI?z3dD<$&e2vvCysshXZj<%PCl7z(IspJjK>3112oYh* zhIz1A;4IM*0O3Qt129`o7M`rSJkA~bK<4oSRe0bS*7R8clJ-y1nZc?#%#*U&% z2$@QxJ^-A!dbKS7c_{zW>3vVXTzcfh$#+dCs3KSy9Rxy5{M|Ckiz|EgYzbS*J8PW?zw_CE0h z_Z*#D7n@Rj)G{m2Jd+A5Kmo^PoQdV|BSNqnr-)>{K0V}O{%7St*M>k1`l71LH`WgHn|IuNJYco~ytoXczg|~Md_$f> z!{++ZaAu2JxlVAX8-XRWS&=YMzsX$2;Vy8?u-O|L>Wb!za29_x?~So$(tQn!1=B6o@&FN9PD}&@ zipv)2l_hjY5NJk-lCebhnffkXb8j8(zR$L$o~<_>S+dZHMHYPMO_{UFJX0s@WgNin zfci88=tzt4w+AERBf}CgYG^fps zFKcR!La&)Fnf}~5a9##S;-;(8t(<$O5Qz+1u^`1Z8srvsV&O^p+`dR!a@hr!huxqk zP7(%yfeL^oumJrENRm(xgF>r>CA?bZl<_<_OxKG4WC=n|vTbpOx<6tCUtMam5u=v7 zKDyHkl?|_M%QagmhEO+M4CT>W0OL(->)bf4_`*h%vWAa`@cmGD{Nw26#P5r@Q5we| zF5uxX3@vF_pr5syq^rm^LW-~e3DLp)=mw8}c4c9}{I*CcJ-wjW5RVry%E`_YPfbAu zaxRGv$quYUSZuAFBUqm9HU%$#V#Th#K|LiopNK%njWR!YC1H(ssN$9chR<_>gA%Od zByUTtgo@#ZL<0!4WAh1q;~UlC)dwIcUoMbe>fk|;$h#dWA;S(4+gpfRc zi~X%#NW$4wFH6WY8w}>RFoZa95gTTV6@Cf_DvowT>e*Ka zVA9!=ir{RMU?-gMw_u9xX6_<+0Qh4o4GigBlsNqlVoT9cz;gx8~7+7 zX**S>rBNGt>(}#BU4cZg>mNdc43s>wPj1MD&veMzBP911^tzQ-?Gq=iVN43E-rUg= z^R>R-Ag|wuAO?u52ik{f)B6bMt}4AY~)G0)>Jo}*8M-^G-o5L! z>c_Ot$UgXU{$7r|#&JJ~Ln|zWMw<}zzILP0A>N&zH3etSMt!nS9O?hbOuI33`e60= zQbj`j!=^yb1L{8a#E&<2in)XyyFA>Vyr=mWSMyAX^x+@Y2@>zuP#(*@KGQ}L55F#G zMcOjr0|v!vXO;rb7A3jIQ$3%&+0nN1Pn*Zw1F`0+R|^*wU&?Gh&i@D&T{27v{goi`$^_Kw@d$| z#?&?t_R#sBY~g(Z0Uk7f-I=0eAhPbJ>t51i~<2Qg`EDfr`#e!4iMdj)VO) z0o@x-LtibWAG0B;%bKVQgk3tE2tPBnO)Rr}9#NpqAK8fgLtsJn^X$)*$MwNA zmu|~=ZuN|st$ovk(>ccstd93Q%GbH+5A%}8x8;!@Ejk(8kpA8*YPMFQ6$tRl&2edb zbE8br{S#;kE@mW-CJ^D(d)V}$g&uDa14L@b`VOs$e{qgbQ|y@E{lgHO>c1OX6E`Q_ zoyn=h-%ul3Y&)rc?d^Hip7Sg#9{0SVGesoUV~*AE9Z z9m^N&&LkntOJ^v)+kOOmg@!S&7^A1Q|3;GxrSOfReP!OB?cL^|WFwNieYy7{pu4Ao z!CEp=*np&ywsvw*v-b$5l4&7io7Xf$t|x^cEAUK!J7OanclMy9Dul0d>*~mCv{>mgZZMU@b|I$I%5nNl+rcO*3^e zW&7l6JctDt5s1rd_hw6t?+k$qs^A|$FO*I^(~U#xM?xr3_Jv4mBH&mUldrUE*>ZPY zJ+=+0xcG;N2;l@HvdJ>>{7WSwYy|g%!~ceYg5oVk_s1buFF@Gw z2kCLr2EZGz|4^!O5w`DTh^oM&jOX_0F#mL3AtGXbGQu4IU3!;UxZlJi>k!r9=Bx)j z*s;RsC|>g=R{-pYz>oyUs|2u9faI}=e1^HRk(Vzi* zM@g3>weS)b?@A`~S<9fUWt=!jF)Hj2MRyg@d*PM)2gnxrdR5^Q984&7(hNxUxuYv| zU(aC5XtX=a+J7Cl4k$*EfDWRfTtu8ZD_4^UbhAQV*hBXN(ggkNxFX~pBH+)}K2HR5 zF-$I(kKmc(%DDm~qvF{~ss*{-4|A#HynoUWEKCSjIuxwo6`A}MnMLRKOT4VQGxA7f zv?Ez?iK9cE4IT}~gSo~!``T;68*dKY7>>FzQgmbN(T$1G8y^g}U1y*_^0ooyT*6e; z&6%Q`bB}J$kKX*gev`ZH){^0^m4ml_McrB}y0!7>*4F5)KkK&uDF)Pt0YAh*Ml;aY z7?{TlfiVVlgMpVS5jH9jJyf#$gmA(#3K@a!wYBJeBjhSlI#1e3r&49A0wSA2q_Piy zE0~@hr+^4FgyMfm+2C&itDor~yL8Qsu@~P$@cy=b+>9WjfKNAzvGvNS(^j#YvWm7z|OZQI&`i8dtZ+PC{XPZ?DEl+d_;AA^xfaK)sCmjz;oZ+fX3qjI4X*d6P~Z= zIXQ&mu^=l}(9N*udqx#?nA+d@cdpHqH=ov7Bqf0T5bz3iTfwYz9bI*By{GSk!%;96 zWJB$M)Cq=1Dq*V@K?yGE8dWw302yh4& z0Rmwl#bHW8gpI>Ixd>MlB9hQFLUFJuUZQl026Tf0NcbXSS{|MTkOc=2 z=K!bx0G#I}Hm5SJjH~&pD+Rr4N&HFRYF0PRq-h8~s2%CkZUt8-#!J@6@2hVz(!-vq zWx^Bx&;=W(nrjLWPwZ_58MryXx>>1ye(ao0Ok*b=lo&QX-bhUFdc5vte0NmQK^Ouq z+VI)$Ca!27;~DdvFs@eGyay;euHBokg%<=6`JVu^{NfDFc-)a8@&n3noj?UX4B5%Dpl(9Vp7d zf&J36AX)8$JM#8|NOJ4RmrTeO6TXF;kAdkBfI$v!jsON85NvEa>N>^JxSsc*)&5&+ zy9CaurADY_-%h3jF&HAwMnX9qnUac}eGfEa+h&Y2-gmd{Btwv#-D=k%d?c8%Mos#Q zXE!#_@%GhTkizh&Sa~CSHxqyp0ZAejH2I00@4iFQb`8yt?`@yII zG&e315by&pO?u1B)A3+1VLn&(w5Cjr4zYcVo&t9z(tR8s3F-gDm2peq{^;$!es$AA zul8woyJP8GRIDv^x0Lmjz|gk;M=)Uy#6kWS(!;F~v15DOUh)58t#&#!8Mo8Wb8TYE z?(0jEE*VNL+5I2E#EXWVJw>qVXx)f(!YxGzn@>ZSkv{NmtIAxrhAUjyxce-l#RB?O zFwt_T>R&!+V~0gs^4H~ZMqDtl6B-2Ql6jN zsk$)LldFzn-R_kzYDoVb?S@Y!MGZqKe8BC=B`}z{&wEw>d2g1w*_ddKA~8K8@zjIM zU<<{}MUCR@#>K~5C5fLiaHac5p=s}7%E9OqI_>;Q97UbC+F!KvXE1t^URkJrMHYW{os;pfD(n_k|iUKf`sJa-c!Mr%Rp&vQHQb{dP%MLh!-J0<;V z7Q19RQulTf)WH~JM}dHssC%jqKz9P#_F9<3iCw)9O ze*(^#a6cT+-TLt%Y|3f5*FX1_VZ8wH)l|Jd&RtYjl9@HaNx<>(%NGk>T>F!{FtG9M zmK=)+^^s$-$Ev060>Kz46|%4Nv9jR(-v01ayJT~>FxTO`XBfCvC7TdCb<8*N#; zyD}w)H|^&C9KGSULpx0#LlOz|2O_r=l7Ft*5#V?f*uxOtNVPK_6T(^i=@0@UEunB? zTI`mB+;7PuGXqKM`L@NJ?XIsshri3bz*&^r_t(G7NLY@`lG~+1lFA`NAdUplO_sb_ zEZSNSE0o*(JXLuX4RRXUa?zYJ=x+QKKhdc|mP(g)x*rW+QG%iNv;i1y){_t>TK%Zp*IgcUr`S3!Kf7y7JL3qKZz#h8pBs7qvtn+t zIGP46i!3(po#`mX951(?QgunnDO)e12CU&Zf3Xpb*f@;+ZD<}lJq6{+aymNE?WC#- z)Q-6uBWBAk$ zE1ptliX`(u%`v+(bjGW50Vis@O@VL8Xf#+#7@5GhP-vmNm8oidrP?5b<%8Wh%d-1a zXfnlfsTU&^RwZRi^@Lp6I> z?^%>-9r@Ol#mUS;LBQ#bHORBinMAqf8{eX&uXlEuW!Hc;R$Odl<|Wn-1Y+a&<*g=6Bag$TX= z?#q%A9Zq*dy@67{PZys;flxHqLh(V7Bp+cdZR-htxG5$A>n}npzzlb6O7WTpp&|9` z%!Ag?Z_gJ20H?mNv(*spNHBKq|ImY3GLNYl;a%0l-n#DZmk?U9t6O6@#c8(SBo4D8 zH_zY57}x(Q2`X$hB^yiM6^xrn3(6tWP)E`{KJ5JllfxA!mB{(eI(v={ZcpsKyE-;o z)el9cc$|yke|?H<_q}(q`DB@k_lGmDm)=z7pRe`?fw_gKSC;Bc+k=1O0yB+9y1zG# z!qq&@hBodf=^c0Fnlqh=i>YM@cY+?*18@%HBNSqwTl_~c`uyx%9u(|J0yp3iSU9E zz5^9T96|l@_8osZ4hl?vTI!E9zoY_MRa$Q~@=X5mLFcz@eI{l->hpL0hx7n_(Epc6 zkC^B6C96+2fB&H2S~)0}wRY)0+*Fs=PZ9%bUB-VF>3@CDF6+JCf0hadTEFNItoO(K z0o&qF{wE*wz{YUPpP$UEC-eR;n`7gDel-s~`5rN_`C;=9s5yDcO>x=!B+Xmvae2B_ zFtGK-n77W(db)Dg<@cO7Z^J)0+(Od+_wmiCv^_sjyp^c!z$Fu^%zN~u<+o0|_n2kE z@G2;QsR(HjDQWQHxvHg?+m)W>D(O)4#DKShfL-2%zCow42=_zMDFF7=Sf3Tc%EQQ#=! z%CUGZ=JZvYPLzX?fi83!Cj<6LSc2c_c2l55_qkKTbC;)Iv7`~2)dAWb11N`ss^en+ zuntR;Q7~QH(a#sR_e6bP((G)9_Y#t{CGFpzh&%p9aGcF&FA3xlflk1zlK~wiAGj5f z?B64#(}vLMNnWKM5~;wURP>%47s%j&@Cw(;j|dpBQASLFp9JCAUAlf(lYdBo!WLZ( z5yJ0J{Y{gA5O?DeahD|l@VofMI@|HIUo&wox)^}QhjFvbvy%<7$aWxQ z(qAhqLnVAjyI$Dig;le;?QoM(TvQm&;*tN`Ca)7$aqINIwH@E$@^#zE?BWzX3I6vs5sjZ#qW5VeO-^mGzp3|fqTt+4BD9#s2U*|vO8>mx;k z?%=Hje%Fgreo^cxp6SjJpHD;Vvcb1C=Xs9O$Cs`j;oIdy6A&XpGj(xq#Dd@2y5qub zzB-u9YQA}HP~iv*@g{25;wNOn!Hncnw;FN~V@n7}5@ZL*J_&Ak6&auQ1*bH671J1B zq%X3NcH`sG8*6oWj2^^^wi^?Ce~SX*phMxL|8n!S6AGm~5@W@`sBl&DCf}|fpF|lW zn%68!#4rdl7vaSy$$TR?NKBNl+ihmZP&`y{Bc%}2PCo*aVD{$<7#8ZzroncU8KvpA zF>h(n04xAG!#-N|;G{zO&7be0rWcEJ)=O{jrQ_3Y$h4P(#VD|{CC`L*Pz1|(Y(SlB z@GJaK#Gz8RpT$K5h|%kA0?r?$XnXKg*m9FEt!z z6rx0L%xYa2ySuz}Gfp*qe0KX&qYUGs#Gi!Za6J^-KIBk(4(JcBAB(cZl)Tc;78_Nn54B63gr8l=6NO z6hicaP%v;V-*Q598#?_v^qTgp!a_7&XR_Ss1k8vA6TA#_fdabc1C(Dt_Jh)DJg_Y$ zdLceH;UHoeG6E1v!PN4)OC9SGDQQBBuVvm6 z?{ie}@7aJJ^=8vu&9~`7sW0GQu(d$OCF$Z2%2-hVgxyGUT&tw8So!gI6TU2H`uQjeixJO<;V};*uRn}#`A=4r@z@fB|9z{<<5J_t z<=&6)#5}IJ{%EEMjFPG5z+_*K3-BME!6qGDz zz<@%SP<0Akjrc?)8*~ywBxp~@u0v#)$jh|WDqca5Hyn`QLck)D3=uCwe<}~Uf2jD` zeRz4|vlVry0_SgqhfYA(emx}DYg6y^O`IOM0b8UUn-dB~(4TI1p@YuW|p zpFyYs_A+OniGnZydX{XXBYsBVnB6E1K#3yHy~e(Cvt?FvTJ^Ceznuy~b_vOxaXF3w z2*~YJV337fQc6y4y$|qca8&?MqglPT>3$j0Z4-FPTeNG9<(mnXkGOzDz}_t;%;q!l zJq-M(2+&PD;O+SQaNu*zj1Ct?(2aZ$%0+cZw>HaQK)rGh39&~Q3V>R??mojCOpEEbe1a{&m$`HkZ%Flz&=Ox83*81b0)^FAJ3(8>{==X1)=MDUQVvqTXZ zN`q4AaNmETttH0+Qx0P66ViwIa-D6xNqk|)>WwlvU69eQuxB?y2?1q0k~m0reBo)Z zd2NxpgA54A*x^?P!uvX5XJ6cJ&E5q1c?5oW05GH@-_GvBj6*X`1Pn}eZ)@s}ERJsF zg}=};(KTMNE++zJbmWmrMQ3uEI1@Pc>DFhl=bbgt-9GoA<$VUNUd}7HTL56{q;OaS zQ5M#b)|tKIM(3xRXVVkC)xUJ^XSg4@ZL>vuYkCC^`qhGN05~EXEHT~ZIINOS0h(;x zvq5^AS2w7`F6F~iGRWOQL8=601Jh-{>KLQt=)RD7@(zA@81ETaR6GnGEv5t@j+MX8 z#=eV%!SHR`ZfB)5hd%fDUpPBF-1Oos0fNQrBJ{BDT1Q5OtiH4kMqi2ECwS253h;7X zx$-A2HwuNLK(`3EWe(V-8$*!B(wn?|P5UcvxL>ICrM<@;cyFp7V9Bc_Vs&Mp!wop; zw0Ge$Y@I97*uL&phJMO{J?3fvB{|+=2=|`W24ez)><@~_k18^wa|@loykM{%3%0`# z(RETm4j9z0ZBHz@rC zCiJ9VU1*mxM3e~G?K>sOenQ6&ztv3G;o543Pfx2jIU&-q_irb#`xk+| z|2R}~PtR++RsLru@cCaa|LG~I7sdVK1WwjNgz!^8|LrMNTWS|7v!vC6m*?J}xmrwW zjRn)IjGQC1n8d$MV50J0tOgetPtBWtSvc^CWkF8MiJL*%Mi+uuO_d2YQ*^{(v}K5S z%<64+2jwxa1og@X*UScGPQ>!dT@-b6G(3wJ+O0!n-vpA=_T7>V*?093?3t*j?UR=A zMhbrvPwxJ@dOqOTQ+?!C9fp&xH2U(=L4?UPXL-50aaZ07N$tl$I0YbQxb6iOX6|y1 z`Bb#oB;btDlZnC}l9Ne-9wo`!s^HuK^Fd9OqrL}^$GsCXEdQ57MgFpteY}(IV1)?H zOySGSaDr1sa0hru|A#{b?zrq?Vx)IUTqJ0M!cw`PVTn<_`^9sjXPFPSHorW1LoPhQLAIPT`}Ni(P*HM?H?sVt#Org{3*~)^ zRA=+Kz7DMM+}42o;#Igwl)GHDI&$oIOEOvvMjS#bGd}7!1~i?-F)FdHH6DO@XeGL z8%l%6xB-CP)^mj#v#z7yv%8$i%gnldGh@w?WZ&xh`(0VrNX8#NfZ~%}0RreB>5Ide z%`bHfu*v~a0w70OE-~vE+r%~T8Xw)i$O&sY`><(vc|aIG;YSnPstC<8{WXH&VqvX= zP`aI0!+_}^)^VX*K3U|2zsGHhZGybl(JrQ2#oDx9b#5rm{NmC93;5{@S7f{B*3dxv zY>){pg`|#l-f1)8mM69tEX`%z5g=Og0c3^+GSZ(Ghm=C|NH9rfgGpO7-}F>g?du>7 z(rAVP!UgyU?s7vT$_Z_s#VA^!zgYmJVtkr|f13U#m@Saj%@B!Nu(N}aZf9dp)SIqZ zuVMhcHyoSc)>UkmIJxfz(Y(*-Td;czoc!+FvTHuOVR>sA1BVjnaB*cQn!?dTRa%)r zMur;PV~?jKUFzFq08WN;bhzfb;53A!n}Msjn4`fUTvl9$+?UeSu@{dlO>A86ikf}d z({TE3jgBbgqEtLRp_H*Z-)8RMz+MLO@+W4cU|*aY&>?n+UMe-sKu{t<(8{9v*V`A7 z(ixM^_+^bMNM9To0|8xMU?9ceQ&C~*^TNA`0=?W+#FUhZkIfzeXva10{5$nO& zD9$m-v!M1uC`G|Y>a`+&L*9#i3ScftLv7K)TthoU?k49*N(&0PaK6Xc*LwR;j+^lq z$g4Cvf>#C&2xL?`^n<%wk|ap)ATFE`aJ8&4duN2IP!&WCXrNn4mV<4fiAw1+-~i?Z zP+^Q=V8aK1JpnyL{Qsi^Rieq%v* zztLb6F1ROtpU>mFW-V`cN(X!5B?|FzC?C4ZMe(p(tHqs$LAnEn>pO~GZ5@zvWI@FQ z6iOqP*yg*3$u3ask8E~z;JLcGrp8%54P@X%3JZ!Fg zUUIwdbAZB=RQG&1=Wf(~tkxSbY<^rQA!KW+mU`lhcZVddsr|g)Cav52r0YA&^*#5u zO{hzrz|=;!?O{SI&j9I#p2=#%^vuK65^{F<#S`JR1!t?PEccDQzV@r}KO8ELe>E|$ z{9V-?AN%W2X?|536!CKW!^W?N|8l5Ie3Dvi?s2*o0yyUpNbmgRU)GT z)}Hpc$D6#7lHL10Pj1sD&MjR6V8{8bw|!Cb{51eW!{A;ARSccC)fxTP0p?g)r${8! z8X8!uDfYaybr3kemQw$wyxhq=x)xjgxl6gW@=|IULnWkXzi9>_k*&B}_kf4!NXt+TjHLm#{au1Ii7tUaXWPo(b zHCeRJx$-leZy_O#FYU||k(bA}67b5BZ9>dAL0BRuR2B)7jOHYv1{ttDkudSsK#Fea zmi*$qpB*=(7EcUf<$iNfMj;TvfU7Vc!sFaMaL{|L0>QlPCrT$16Lwa_VRT3q{2X%f z-pEqC5{~qE=k9Y(_udZa9r0)oj>?MNvXTmBBpdgf#gYFULm_+O-r5EEacm~jT$hvgrjcC`?L-!qoA87(wdx4A5Y>bO-y2qpHKiZqSRNVK<;|e z4y+GgC4G{Xxbx~oWd00XeL5w@NuZtIl}bfvM?zhV#{8{cy}q!!)2*T4^cp)RpMY7X z!1w?RIPPQM=NJ4Haf*TpXCu!NP$yo=JJEfXinrdBU8t|4NV9oZUa1jxBlx%b29u|_ZjHD9yl1N~j%Fkq>PSFr# z5)BC<_;BD54px6A8X6Z_A$)o{-iu#EhsS{N(*?g%_#p(EaIy$;6>)@u3T7qVI)Gpe z!9(aE3BiAbi+tCH&`HI+af~25{JDpA_7eq>%kuaupWU!iIN~x+j|Pkq!XL5x04UOn zh42PV$2(A=b#Vz~ObiRY3`0U)6ZjzKmbz>VD`;?6|L~=l;+Zs@2vE}Fx0ivgq+@Dm z8CPgXS3&|*`#dO9t|VY;2$&$M**CicCx*axMrdlNf?3Du2VpeH=Wa$#ZqIrIH_5o| z9`Zgccs`T=C6^x*kk_B^;k+giZG8ncihV;F`1BX9=O_tU7+Bu zz4gDI3cERSTFwLEOhe@n_^uN8a>#t=2qD3%2r83L#(_`8A-&NHk6aCUL8Tw)&}#Y$ zC@@ri!1hP;Zl{I6P8%hhDMB7KY=heZ@DMT|7|vZ?BtYYkwrN*MT-aVpEX*FExgPSJ za4u1o*gyh8xjTj_f^zL%*TZ6x+tY%ZH4K{kfYK~7GyXA?zlDVfV!<`;n#a&F%c+d2F?;3S-8?u2CeH)}8IU_{ZKt=mr}o*VmHT!e5$;q3mBded#4mf0KZkVw zcf{3F68}mhUkIKi;2MHdExhig+Q0-tNeZC=VAbgrepLP0NN!uaWbQ%45f*BthcA+V zs$%jp>6k_q#zO_;%R-e_VnRr<`z!H_$$17dIM^|b!C$yrphIT}J0NfNuu@ftH=J{j zjZP;a95{R}Wd0ZyrnnOQjL9EHhpXG8z;wlghgxNkbb2s2Fj851>r7=;&J{B7lu9c7VIHO109F#Z><4 zcS1(Q+Xlqj9(!-w5ujKq_7C80003H4c(LnkwUbnL@TYcz;5Zf*L^*H&PzX$ELX7T) zNdYB96r9K>_d2bFh{*+xF&ff+02Gyh{HhQFEfR{e#0&8f`0QxFjODRRNx+E>9~t~_ z)V+69Q*XnjyZ25{NU~|tAxKqF10ubIB27wAR6x`S76jB_0|7B~qz19j)F4PxF%%UA zH8d%r1VsTw4T2(w{(=P&keu!NezRuQe6!ZftTSuQI)B3-EFj5#?&rR*i>+!z{Z3!m zI8gP4welerfVt#Vo7|yY)dtQS>Y0OaRg4qK;Wyb*g=fzDKiW+BZb-dlDB)AHZ|}7T zfvHt{|A#vz?T?DW|8}Qz@5ach8*k@th?HyITh@#R)O?Jt`BYdlb+2anRn6D=8nN=t zZCt+yw-D0)QIP})52hV1H1y?@G80*$;0sgu#2U5^@n-N zvpi_Ds`1APh*7886db;Jh3_`~b?D8UEr2Ef)S9{}?Kae<7hO)ih7_urmo3jN@H+A^ zG>$c8$`etHy585mmU9TRwy`g$$Ux}4A3%dFjE&&v-(3?IwG-yBMSqKvpZ%=HRGJE# zP9|>CFZxM+D+VD17sJEWe5Xlo#4x#73nsFb09mKEnl(3DG#5UN0Y|lLg?SJ25P-Je zzAvNT>r96d0f7u--wgZha(qx%6dd-sg_dc5C&+jW7Z|Lx@#Wa~3NS0jpn{k8irOEB zWd=*a6hUjjEm;?1lpR6B#cmVQ?&qyTl9m!)*!BU#U2BO54k3eq-&AaG)m)<4Y_bU3 zA<$g}8dLc%Xv_ibdPgT$MReE2Os&h!Zs{gHSOB+`j{HE7Tn7ljI7HA@7Hn|dBV@6u z#WJvoo@l?@q=!Jq<7LTz7-2Wz-Zn$SM}ce1itolhZn-7Zx#0-)`8N9nq020%yVaw& zajx@ZMw^vs7s%QG6>l-yWAK|zH4y;GOrS*9ZIMBQSU5E?kZZoq46`}^dUx^S6U)Gk zgBkWI{gh|h0NG8rd%Dy`PPYjYkY~r-nR*&Wx)mQAylLC52Pzv&uNWfxyECK*6Lhz7 z8h|dQ-&S%lV3DDK|8@s8 z0@whFp#Oi`L4|OM=T>b~H7<7jPte<8t~-$GTkRY1-syu|o{U>hv0MGWcTm&%M(>vy z9>kKN#1GnMFS`C4EVC(R<-@Z0@0d^Jo(K7{C1W2m9#OGnIyMx-9segyvl8};p#b)CQANTL;XLx2SFnhbd-T5nVy1aMzeG*BL zo-TL)gk#k+70V*gGECc^$Ai6p>qaO0clm0pN@0TaF8wr%t26rV%PPOq*0cGI*=|jD zzfbT>7&B*rA7w7HdHHp?Ej4GkdzP1(q^In(cj4LI5@ZLpRMqx`bw+BxQK>W8f}Ljh z8=7b=^E|76=7r~`w;i|C<49p6UJ=wFiOfY-7$l4f>uQ(tAHz)1<3o$>5t{Q*4-I~9ciQE zux(i`CU+B7@NRP<;Cfp2tj^?z3r{`IKa<}Y6_G5z_p4&A8yE=UG}uCEJ=L>HgpU`a z<~!DhQAaE{d4^Z_rH?wful_jssWjRGEv<%SMw`5BRQA(24Pt z;c1@}#bZ>@hC6gB1U8xv?|!iN+83A2%y?wh;qy^(|CJN&-OD^Yeh%NBzWrI+J@cSW zchG+QkL&NB5st237FgGQ=E@SqQh%AD^gy=dSKZ#4GT-KwZk?>kQLJ8ZV~MjC^?S*q zN2-z2wVj7X4)@tf#HHeHFU;tL1A%EEL{vK}HYU>AGofCiiN9c(NQR^0uImw$9w)tH zL4YM!{`qbs1w&|I9ze^0ucMHI+WZ$RLos1y*o@03=3UOB~a>FgVrxr_d>?$tT^w~AzMNjO`40_3YIO+fNxYc|wg4{*I88Q}d z0vL*y-v#H`%(Z{dk;{mEYHj;?>(0pO{@8;Hvnu5$Evy$uw3fP7=^%!`s&ngW^SY1sU+&VLa1IRj0jP&o`EQA>8q@72dv$F`!-%+!d* zV2#B&7G8p(!7_#7G+{(5LvY98Kd>;90WQXI#XP{D00PUnX(vYCq<+DZ!?ma2Gv8Ny1s|C`BR^M^J!CK2=*r z@EU4E88h#l5Z$~Kgm%%3V-(4~Exr6_90y_MSFLuPE)5kqs1gx{Rq@!B---G%D_-dg zO>d&9x9_z2s>#%A+=XApW#Ep6f(AlFY~}Y(!LIVzm2Z1;p%$EN`yJQp@|Gxte9k~` zY68?ys{VdcHE!2f;&!RBtIq2-s9q{{kC;N8^4tFJNg1oPY)LWYw}a5sn{wZk zR~)1i1EB`mYII50JkC}IsZ}^!jWHitD+FN>Z9I}sO zj_H3I>U>71<6aFOGvX}=e$HLo_{MBZSIbEUe$~47ipK~2L*=fUQ-qg%H)1!_Eb6={ zYaRTco5n>-JGL>~t~{OQs;c~!JpRS1%b&33hFYVP{{@yQ-WNLVKpkjYdwFItbDzGW zik25 z9|#S2R7Y1T-)9r{>&qdEmLEviD-9eM&JP;J-O9g33_scUk2)aNMdX?q$H=KXZ~ec& zgZl3!PXDWQqwG2-`v0bW{(l!N^FOQ`)vq2-Qtbb>ZPiJ8*tM@mcHI!j;7LAC&h2aJ zOZ>XwjUK>F?R%p2P4M946y1npp~|AFTe3TAl?gQflt_!_FTbRpkD>%}mr<4KQlgYqhH*>NF!1yj z9&sIgV^SB`Smc@CFVeIrLGI!4n0XGhYApd0Bi16^B#pWjLqr4E{Q?<(5%z_{vBF#a zRuOUdwFCfJObE!6eA0Chb%Fc0A0NXvN@O9~3NA9j)KO1&O$io?cMs&twcMdDu}+nV zsbA>SB@yAeh%zpw_6qb6b zj>Dwah}TF=y*Or}rA30+ZXl3ktEU!0N3G$b{Uac0E_4{iRnerb0q9cv7Hu$`ewCWr zMOotczIROhN|TCYlP`X->N!VUiTrX!XuTjkQx~O5ZJZ+uWy!)E5`#DNaXgyTeKFpL z<8C?=et(wwbTDa3Xg^oFxpxy~Kuo%eIIzS)$gQy-7wcl5ZqccQpmKM@fHe!XmW|UC zrpM5wI{AdhiooUg1kIT+C^u$&DB<#R`}*08B|haEn>Z>C(nii^qG0rB=2|^9P6+Ne zQcU8b&BV}g##R%UgxHVRY)mpks)&gNB>-lwQM$t!_V|=^JtgMGZQnz9N~VzXj~K*? zl{Sk`-5NUb%zgzj8PPp~TMMH$vLQ7#wi_u3(Qs8_zd;c$4lhHofbFU%`{bPv<;x;W zsb!L{%HyKP&oUzA{wU(3x%kt6J?W?jk-=OP$~nW7zI`yDpGg&^%#Go=TNNDHkcZhRR`R27InKuUv6s8}V2k-uxeW9|t(Nz&^gbnE$hWA; zqM+j?75{^($v>+p>Eha?uCfym2ASjm#4W}qg|ma9_zP@-)MJ1=z}dIfE!c}I1q!Ly zh>NwqsD>d$GHLre#%<@?igZP}X1aUUZ^hUNNu|f_+J)FaAlqdW$(`08Wn<3l%D{p} z=m?*^$Ij0t63{TQ>8|xiK@kOWNlK(dbv=59NxIG_)i6j^G+eF`yn}%=?jkz4llH@a zOTM&1^2ymeGD1v|Fe%q%?VDxeS2`J!USUJeA1%s7BcNtmHm(7tRPc;1&tx57lGvv) zwt}m=B{`(p%YXdgp;ShDDnZ(WJj^iOG;fcevKH+JHs&sCnLM&mQ`(b;tK?ezVv^Ys zF4{|oc4wk50+aS=}?%od-YHk-iIm_0} z@IVnJmO;^4OXc%OqX5EP#bxqIL4{J2OiRSD5hD=mg&4R*Xa+~>D~rMt*VG7zI&HYEoXRW~ zW^Ipj-(G5(oLO@eg#w2Sn;3(12=S^s5EQO;xWwo*ahEWzY3C6S@W@|z^;ms!@Oqz` zVJ>PW?CD4Qf;e5w z7F&pbAsxIruKJ#zgD4$MrL3BzCV{ICcYXw&b z&}XfVZRQ4-4qe-B1mDV#omdYaV|nU|>$I8hhpoq!CX}P>eM-~h4u5YJ8kix{yQiqX znbi~vWhyupB%?@JP!EzA$TlhhORy^vD7_I=%Q^J!tGp>6 zmN%^+5UERX9ziXjsu(b{_r}cFYml2m=Ql?++|cFY`bg1NdG_5evJ;Jn979YMQ&N-@vR&3kCB#PkQ*~ z7-BBhpVyXamKFnO_O2PR{j4lm6()OZ$cbALt+athZpW|X3FpCn6~firR*@FF0fD-Hcp-nByc<*eY6GrZeRd#@-b3v zJr67O<_o$aCc5rV_JsIaA_^^J6J}lJ+`n%715;3jA;bU#Z4=+QJj*xNd$K&jIy0TM zN+}coas_~HA$4LM8DK(3IcOPRT|Lk4OFdO)Rd0J>|3j(no2s@F2@j;gI6w^L0|e_Q z&k+}u>A#vu>Oau{AKN|lR51PI@C7@sll`M(%&@VB8ktra8h6-++{4>b@6}DTodwAS?iACN-h7JpKOy0wnZKb43EuahIa{xF|vJukXw_x=b4W`R*0 z1@$&e6ab;Q3j3Wc?XGw@fZ5*^bnB1d`sW~YJ41)56!RjmC^4% z|L1svX}0l~H(#XQK7NAx=Uf;9914uWbwoP%_fm(WduF~IUkrQ~Hksk2{}!p6{f0+> zvr!Ws8zo{ZhpGX=jlK&uVL!g~X_WcSmQu)q{=1%b+CL!m{iBLYk5z0V+YT6aeCg@T zvdgaOUm@%l!1jheAOaI_Xe;u{db4`_ONBr7bM-eVVn81T1S0Cz4(b{@U_t|2)u`d8 z_lwm=zS+Fnhtzyjsk178Dh)uffyy4UJ`{jM#*_@Zpw-(C*92Bt_rANH0RmkK)?LD@ zA9owT>`mKI5j)a*Kj77ev||_m!f`&d_y~nWZ?q0wW^;!Mu#!EAHk#ymLB%!DiSSPc z6vpOJ9T?4y&8k3#Er>0dLfeBN1LUiJmSZDuXB3z5GBWO=Y;HR!`0QTXE;!i!@Ikw$ zN2HaZETecjRT!1R#;4NSpRR`c)q$rErqMprKbQTl2cmBk~C4@`Fe8d1pHXZjlQ}b7<9?dHl{)ztj zdS6pxgus_}2rR{V03V;caN6f}^4`xW;c)NLuR|j7n5a!d5?7p@uB?rHRgSKrAiLi`#`6#eUe4jFsaJhWbt@dow*A#^ zk#iPOWVZsTtP=<_NG#iDXE4OmK49rX&sOkX{xZnAe?PR0t_`m7_qjpbmm z)AlH!b1rdz$?W1L3K~k9$+4N9-t_6(sc#Zvz%=`1b)KiW>jx*`;Mc^eD>nhU6A{G~ zWZTUSB~oqEpF#{gP&waclcu}!>Nz~Z)_1=Yv3c_9uYvD5>cB{@0Kc$XX|FXXKJo}S zzyUb;n{1aGw?I7G6}X(VykCz1Hh&T9`Jya1{UBxAzxhCv#W`2lPE(tQRX7XL9Dy3; zLfsbHHT2|`cUbtVT{d2rf~ms7j~=hNDV>5Cn>2YU@`|FM;`vzBZ+$#XL*eBiDOQU* zRf=~MMA2_FfUayr)^yM}Fu0hpPc5KZx6dC3=$9b|`kkx@%6loq(AEQ5|j#rvJ>SHgCAWQdXJma`Lvl2V6PRxX7tgm0bH2+W1MRmQreIXRA z=!x28jDk0w-*utlA#w3XoSJ2G6Nc%z|2c-AiYC|V2Cn)!{_aI|<1aZ$hXTq8#!@#n z(gd=ahLhgqDY^kmOM5(5GfRFpcFI5qj0o9sjm+SIO0^!Z&DkYIqmboBF`nl4m!nyv zgKk^uB#=;zPhjA77UJxB_)pJuE?1?;V|(K@rkTD*s{s&~ zFH-FakoM>BGU9>$bpLCQv=n*mX%Q3IBd7D#W)LLxe65w~K+kIZxf0!JOty@XGYw!} zCLtS|?4)tDG0;t7)}6`k-L0z!#A5*7cH0d1;cB6VF73>6?z}yjAp{9WdFO5()iK;P z*%R>W+xZ5k7UeQNHUiDEtB@*p=cHMixpwAv`J#+3Os4F${9e#^Hd}d|OHcO#jNiRV*@+whaiZo|nyzCDeqiZ|WbvnjbbSJQ3}UI8o9aY087=`PVXy>?75_{?CL}0q1m*UrlblQ_amf{PP-%e9f=Z{bgO@&+8$c*8&E6Uf#a< z^9DQXTHu8H;JsHr|3gAG_+b9$O%C}w3%6mYRe6@5=6O9x0g+Hy&en3XuJ6{{Fx(R` zTlZfiRME5bJo1eYm;aLms)N6-{=Y9!{qIYtoOh#TWqPPuQ?yyya(PGV2TCO5gP#A$ z?s(>?qdY-lHZAYWpU#?7A^^bqcBW8oU5}gVrFsg)PApL_;TPZ zZ#_=MbcR0A@Az-(v95u@b)hn*tw#V4a#drh_TCJ9 zHS@XXOcVLEU%N^(@0YS@6f0dRkimE6UAVy35cBKE%ea>fDHT0`_^EacC0Txp?={3} z8%>aBQ0v9QugxD?9rM}ACP)Moi5HM}aFR@;I1p_paRuhe&-0DyMX8;j1Pc9!dQxhF znH-dBJ>ruVz`UgKT%Um-pv{fejVL{2JIeeJNL-pZ*bQt*Q3P6uF(8eY4zMrYku=gO{ev6yE^new6>XHU*E_xu)7Ua&}aX{Qbf(Qotuw*ok1c{5^9<{^Y2Bi~gV zCKt{O9_?u>Ce$(zqy?1y0h)RrV=Q|AjPZ$ zG~yskm^4MMIk4$`VkUt8Ie2u%X!JWx2e0xd){o_}-wsbqP+KSBwe;Y%>jQ1&fB`1? zLBxKHrqn|i=n_cvF{EEBq~IdsEV|U{??k;B^{V$Gz;`+x!VKMulPha7&tNOI1(ab8$z9D9l*25 zh$b9SSG@tLtIbsJ_{C~%J>7BD0V$BFV*AnVFyXbBxB)6%#K7`S_-oNT+uBx^<`1CwD7}i9>Xf1|57$J9qP& z&JVxXBX^Yhj^PGb*^fdnS$yf;{^!l3*jJyaz3E@APSc-e*|hEhG)34q709=x;YRHe zf1SKnfi!BRrhXv9N?FmMHP#XEUju9^J@(r{_P#sK!VVx3-!;YH^$>k_v6|xDtXuyMB6ljJCxpz)u z%68}VUM<4;AQB?v@Xe6RXJ7hsny?yKO3@)h0jL6>>t_RpLUKlvF@gL8sBYPN887i4T16#TvPe=eb#zlv~)f-K8- z2bAxPE)OXz54~3&{;K@od^uaW;%|YfaNFvw!K#}0=zA3@bk=Hxv${y(h*p_!4}X%# zO88BkV56rc`{5iD5ENJDYFC||a?Q1@QsRLd5iAm?@&)qRW&^MoM4}FL0l1t7fsAS` zI)o~zCgoPw6;^LCCS07~nVSD*?Scv7L%DLQDtzTP-r)zfnwcYHPGwCU$EKV*%cFD>e|{hu2f_JkO&%)rbY+vzS??oDgAmXRNX7F+&u?SFQ5P< z+b6lH&Il;>Dmop4`n3R{%3Sk2A#P5D{PWjJUhM=wBfb#5-fz^W34a}%55Bu(BgqAT zLy9#33u*{DvjErssjl7lxYq3T%JVX0XA%&`A#mAuqEv`-EZ`s)^DIK|evg;Mrv@g8 z6>&EOAv^ni*1NG*PgS@=202ap=pe;@fDY&jEY|a|-hw@#ke{YP4cmY>S;$O(eVu*9 zspVPzRyu4WzPCwyZz~7$aWotwB2OHtO^&JQUdjLbN-ypk6}JtL7orZ*O%+h)f%Hv* z97x*$&l-=qr&k~Tc;}{VYs5mM8(KPs0N~eolp<+4sx^pYA>if>StU(PDzBT&RPrCo z=yZziYiyOR7)4)M3pl)7xggMb-gMjN@y=AziF5-JC^V0#s(<=EB9P|!%p{CRgLc;G z{SjDlBdHyhgtEs?>xybBGvZ!6B7HN!Qn`S3F+fD}cmOypzWY1x`W35s<;6_3qI~u1 z^|TS_C=8)^(963>4+?tHM!NEz-{!M&hWFsW;|H6I^6#Wl-y4%qTvRXsSc$0P`P9O} zyUko`e$ejq%{P~}-7|gNA~0Aj0DypuhdUFr{CoEV#;)m3ul+Fpa6w*hdc!SDY~$fE z!yq9jE2{g>>L75S70n%`G8ed!?T_9UwtQ}CS(~X3v?G65hzfxIKWhC{K|LDKETnGF ztQpwQIe+ZF-*Vk)v1Kz8K+^zqHf2sg@oWVl27o98{bU--M<`S9BctNrrdNAV@h(uV z&IGSsCK$=`bg}l==_6gnv4AWCLK#7b!0MSQVBOpHBKFDfb?D{d<(JJ*UK;{WMs^;L zrC4*G7|`HpHxLC@fug5qun%hw&c^mB@WG7$A#=Ld7Aws~sL+;`L?dBxbS1cD)#(hG znCc2pupO0BL8x7m!osJr@$x78wmi&dk456IA-tvzJ}zRzo*18(YF$v z=HSe_A4UC7?rqg;Y@d1rf_`CjaBK11jh?_}aOuxjYF$O&<$vRtKiQw#dRTvZb%Qgt zoLOr8#m8}lj9Y)U+NNK9m4i3`){v}BH=NfEJtzgxcsI7)J~-BM@%1v!ncnrAn~PL1CR?)>_$xQV`0mC;$OHt5|y zck!Bfj^+0wVAPD{V1@T(@n0PCDZGwg>iELf?#rEPq&cuRHuII)Kk9aI3kV?i?}Ezv zh(xE$+gc(<^h6-%_S+=6EptV(UzGr=-Jdt#`^<2zd>0JB`tE&7GK^HONq{&$eu`Vs zXS?v}xmO}IzIzmLZ<{Ng`ZZ!s0D?GxK=sexR6#twsn71R6axjQ=g;NXd^k6FAqwjL zGGoKqK;9Hac{dFpvvy1D zlU4K-h2G`Aj#huJ(V7%(lf`_P+Gz#r^IeEC+6FDC?k(JDm{mFMjFBG6%PDW(d+kPk z>$6|!fYdlWS^41Eu!DC4!)rTW9X!3$W_EEabNOq;Z*@o@b2jV*^Z)`IJva!7TDo98 zM($7p^1fz0Ckvea_{JdO_IjqPmaWuMy(8!sE8XAeYx1w56uZ}Jc3SJ7cEda2uTFid zYU@){O&mR=!m5GtzT#!O) zNX{Sb?FQ_h26AK%Ch^a2hor=4BI+z^{FKSzRli2;XMFo?HlW4MRG?WR$XHRYy<8xB z>vm$;iKBWo=58N81b71`d9eaB%il*bU+F8di(@19-k+P`g*A-7Ir07aMe7BrwNZGa z*OU`$oxFNsx&_NNvdtm2>r$VU*k-=c)8<=zY45A?vYG0AzCCh6jOKvQkhsqx@QDlq zMC|fjc5iNt-TyTuw`S=j0iUE|SFalJNV@#!xlLyKTqB&+8}Ba@(8nfnHk!*R(|e8D z6rGJAbAiOOP5F5mmX7ty4DuM`^y7KxR4@~Ow3PFOm$7b8w$~!VCRCFXD25bn^KPt; zEFlrU)U_;&OFE?y-gRh>#?@z)VAeLG3@?crR7Ffmt!NiTa=0s9uYt3F)u&PElYa85 zUrQ86bN$-`UDs=D4_1MG$IA@RaK4;UI22#1{8o?}iPs|f=(n4u)uz%vdStR=Pph)O zDJ$OyH?bY+VC?qmuvH!>qN=dQ#iLTDXCc)%Ce%W4M*CfNC9Dya$Q)A4_pfGR)`;yD9*UAw3z?Y2_+HlD zct~&aOwQnkmB$}W`o%E2JrZJ90(Nuu@`cQ#mEoho_2CXCrvS``gy|yWy-dEBlOEJc zDJVh8tmutN)Tajup8OyvG;)(y3G>cNm+Y~bD3GjtllVPUmIzHz)XIn zbjs56%cP4s3cWOL7>4DRW>x8Y3T4du5nM`>r>xq)f_rLp15G4V<-WD&+4*}vuF|ur zJodRiFMRc*-26$ES7gugOY=V}802bZs{6nd<)4+Vp4AABd7#|#XB9K6+PA{}MRmZ> zYQHDdTkiC{sEPjnJod>Vq?>_2~Dj z{{*jDa4ndC4Gn)cM$rOW(7>lo3Sq^NDW;$uc**8i@?-^tie0)8|McJ87|3&y2I<5f z@+{m{eK9qif$YZa_SiE~uRTgGo@z$6i^vk>g*m13B4GQ?Ou<={;I?lPZCwTc*+OSa(M*|zK0x(MOYq;_ zw4bP1c&TvlgTJp9XOpiMWibD_oyRVYIj^7K&mw5J6~0RIJM7TNgeuo>$LI-5d>52( z=5f-bqvMVmXNbXfEdj`k75}o_GX&rPeFURjgQM3cmd*C=nadxOtHI-}W~Iq^MdV?F z4xo{nHETu*@y450Mo@S1_cD~i>DfI_Jke*Drn_q2COhqJkK%SU2S*?CYaxDQQ*b2$ z^6t=8q=Dx-F*{#hm|FRCpsX!N=S`35T^`ot>1a;e4=oLSiKNpI&4nz@OD?2%-B3-C z6{nAF>-VLvm47J(Y*g*ixG^egJMNodUgoGi-PLI=)sQ3WB*5()f|@sHr2Gi!`8ar6 zJHodT+AFK){wc-Ikv>bSp@ZG2E=Oyd{aL#Zec97-uL8OkY>b_ ze=dg9?cZVfi>bNAj!N_|J!l1j2*t`+YA)Pn?@6 z{r>fr%aJAN1W1&5p{C=#gFvj%KCJ%FB$wnQI97yn2k9sMm+O5`JsE;NwEIy&I2>1& z>+`|o#2-H8o)}wu=Y-nUnA?MKA$Ovr0L($oDG)f&B#(LVQC>de@Mkf}M7USDj|#PzF7lj9x2cIwH2xO9GVl10tpJOe z(582w>>L{8d!cHH_!c`4K*l9RMx#7-SsLX&oLC~D&LUzYp6oRJq$D@-0M3vd8SvT+ z-p|Io9wgje3zKh2Bdrp2a*D*|#BV;OR>F%%MBj1(q|6SraT2#4iBZ~g3W1~kGt1H0 zoOZ3l&L$#BW3$Xs1$9=aaqa@i4jB;8|HGJs1P{0?G*Z{`qt4#@%A>0{%!{9Fah|4=cQ5(zb=O)e*L8G@s}JXKPkrZ*4py;U7<27H3nnt?QS{HzDct z7P_X=zb%)aLzYFYk~ za;vYvxb)Hg(x(%bru;7{3BV()i(mG{JTa02L>D1V2&6%Czd{IMCM?p*{@F*pYYZVRf!LNSOTsuaPX@i&{!I z*QWu7OeybYaZpgXXL`9A@oHd?JeLL>=K`Aa^|vF?NLfPJ4}dtRDSqaLXH_22B?;-g zq@MCXP11Qw;54F60toFyLIyHE5(6=uWrtZAZ@5A3Q&o-CJBW3(rf8pUwbTzxKvRe% z3YS5-4hMXYV=u;zzZWMYv!hZuL_(6N%(U*>);ev6033i6{{UBHZ3GHY3sX0DC}Bcb zIVu7@-tKGh)jJYbR%az5Kxfo&Fet6hH*J#%WNZj$fhfT~j*Hfw=xgHYl4RvIfXte| z;1_503ogENeVZg zz1s1jhsIPsN^g_5oJGq@0}*KKPCD|oL>=!(PDZp#^EJHrGRus0Y3T%%5KH(D5QMi0 zV&L!IOH4en{G{2vhG3POQen4^OM?$^a71Ju2A|cU{Y_a=Eb?a}?Q6yIsG@5n0k?e? zs39u2jcXCs{o!#0@N-Q;!q?1PsK~j-zjyCWVI$S@QDy6MYM>FhIHNH=qwJpLy~!61 z--x%=6p)qB?MP1bk>#|P0I&|uh_O$+t#VsjU2a(&i(uNWMk5^;=r@zPGKdTbK{alp z&wN}YsqTb9o$mcBlovk1M&}if7Ra-H)gcjpq5&{p0cG?cP@4RfbT{Cz9iAS80#!hU zjdth5DOfPS0p^3t2^sZQKQGs1KqOUw)GN^CK{Cw(IS&XaBcb{Q)Nll4%)5MVha}!e zt>WTH0f;mg(3+Q^_}0+^SWeuE@Lm)}mojL#|9L^_IRQVnxJc5x*cuJndR$LqUlf1H zMig9XFJ+%h7N-h!rik02{&pwT4vbNUQ!L(774Ww1*!|xPi=2Q2aN~b}q7PJLZ2K1hdj6 zUxy^O+R+fP{_UFbC2g+S@#Nl%YV`FTIy_N}WBQ#_bLXqKBSi*;1XE<{a|Fdmk&^xP z@jlNCwex}O67wTtoYJKq*) zOiYGIW~$X_>f(P1miB$t7JN9q@Uf$Q@axXocyJ}!@4NRKo0z%bKUU8sG^`c@s8VAM zl=*j9q#Gq8hidtbNP;K{mlI7UU@%;M2QF1h31yq~({!G>l#j!l5^NQh2sHKgX^iy1#noRY8 zJ#D6wl)SAc7G?3k0c${@JiM6r{`4yM6%)lr>(+TAHTwE?AW~7#cI^4g5eM)fOS%=n z4MYSUJZ3uesnluR@xA{R1?BIJ-VbV4`XsB^(pj8PX@}6Ms><`e9)M1o5diQXNr)VT zYR*Vh_Ej9k60w{uq16Ix(UcA7I``KPG_#&!F(90-e;Vi0QL&$0`08fs-fIUgF6wW6 ziUX`Ukb>10ryAuzUoeHLsYnCX{Aq9dbo|+!0BiT;$Q4`pJDH)Ii~50+WN8X)YjYg==RHjagoC(10wUtJ#`tc%biBoI4 zR>KBRJm>@naLR1DechMa&%KlG`Dgun&Azkw?_nN^L=Z)i_ud8@NxTCPDy#BKlvIE2 zDkDN)&~k2SF>y?G{~>+z^yIAvEj*44-cP-3^SF(g4apDYFc4eU{G|Sgla8R}59_`O zK*+Suk>Hb7SyfKd!~kVgYjg6a=ge`yP4)hI%SA-)h8Y`b^RnLMEb0F`uq|8d__Rmx z6O#|DeNTQ31L@m=eiOexzvb^32?0wH3q=vX7B4OAR+Hu|ipLns{C_`u_i#}cV4M@W zFw!+O0SpJgIPKx!nY?(a6bF<-jDp&%1jSw+R;3H1aA~os{hpu;-caAko*csLFeQRm z%ltN_@Wu{ed~gwKGdej zjL5Pw(IoESq0JWsXnn;@fLy(-*33?)7Uv5?={8-!Vv7#GF6{QI&nBOJabr}&iiy<{(KZ!X% zs(dR1rErCxyoy;;fQ!*lVoGyj{csxgg?kSDtyq|sofk<76ew40^0B2 z@-%&O%SGJE1Rq7;lz7)4X7<7W>Ts6NESKK_nWybcQKAKS!MKO z#eL=K=a(LQxoZ3WpA-H6j0CgmRo3MHK@!Y=I?+Gnrr84R?VdBX&+4&cT6w z?SmvB*NzUU(r7B0ZH}8tw&K`epCOb$JaE7PgXM$9Yc% zc|4*W-C_NzY3|#Rr`=5$Hz1#cns28-p0|}hrP1*?vXEsL$FCKl}x`5%Z+V0(taGOI~$Vi z>PY_P5q9TmpngI=?7b2mf8O__Ue!zwGB_5ja#8=More)eZ#s!$!Q?150?AIVUiNin zLvqbSUZ~-qKD4H`=7-5%S8rt-|HD|V>iBF!vNuHg!~hkUfJWJ_H+Noqdh#AlH3806 zjP1H@&&%r4_1$$ugW=u&bu{PHzirKX?@%44VgPb5|yjFU2H#IFRtkXy~qM0S9N}m&YuYD!<|+uU*Q`d34_a zpo!YU(o$JbAEZ?e}VRB|HT zOFPL%yhX6cE+N7hDZ3=cWe^iO%#T*wv#ni3eTT4KVEh^eYJ(7~LxYsX2=p=LU5h(* z?W!lcW3e>oQHjRt7r}R>Bmamf2&VQL4bbDPUKP1bC?Y*#5s>P92pw(4MrkoXB^tDf zhJ}$s<41QP+Vs~lV47wQih>QssLvHR)mt&b@$lO^RFI37Q2;_=oD4saCcsX9OZ>Yq zVS2j9liZQd&L~%ZRz&A7X$_+d2H$myCa75`j=l)1u$gmfz0M$g<7S2lGNxD|1cS|B z(hH9>MwTt9Dc@&9SO^J#zyWWzt${{^H`JY2;Az|h038nQMoQYf%@|)K3lL*#VA2gv zdMy__CMT1VD)*a9$>?%#ZNY?XJ@B)|d3oar<4vh3b}AehUNQtjEwn>Oae_ncN+TcQ zx;0B@G}6PrnXF=QFw!veX_v+e^4O3qfZN$h!Zh)13T7XldH1B@y{KQ}<2K>34I~qM_5vT(X-nI5(#Hc{xJV8R{dLuuB^@ zl>Aowm7kOJLkROf@b zHIo9t2dy1EGRW|(fPt?ZQh=k$n5K8#ai48Mbkjz#EY*6&Y24?naGhlTwhzAWRT1XS z9kP^;I*dE;`8?JZan&-^IwrAPx4`%mW`_*0SLB6+Lhni-bcqiMb0GQ$hQR{#0J(Q3 zyo5i~AKF9c8C2_#SNlHt5osKjh59+^{ZuIz$0aDKiv`0W}&6HT9@VumpPY2 z%N^R6nucJ#LxrdnoK%(L$+ClIk!7zRV>JsOG=#eX`IM|VU*>+V%;Qy=*L)dM`RYc? ztG)qOxAge4*jEGYT@8G7b;tj-$PiF*Jh~#PumUME#J;MCo3G#~S0-3iCIwVRuEej| zVwK01OOOaF)1q01M<{umN-mv%n3K*IR^{KTDtuLSP8ldH#HTP=8xlhE={QvutN;V2 zkQ9WactiOb-}0IQ8&s#`GU(ONmg)&HVIy+KONWrhmG+g8uPM~(F4M6RQbm|403k=2 z)jV~L!lYoO<(kK|w2jnWGJrni8^FsGl^?H>IOJO>su-qb<&hDVIK+b%#nv-I$``?! zVdnC0E8!pRH|M3vDDe%H>5Ywi;6Q@1lrk~CRm^eG5dXv}EN((p5AJ@){YSG(jvwu_bS(=D`XoyLDAglWw zj`3H)Y5s-sNLB1rez~ijNve_P)L3oc+bmd~7U&V!&`T5ec?k;Xa!;FheRP; zgv~ba{eVaZ<(1ITQR>~6+i5B_=?k^Dg4HfbA`MXjU>OU0Uk?t2_wVe&E&~ke0i#9k z{fA-q{$TE8Tq~FfquR|7)e*8UKaTLzBg_>!>Y+Ntw7a|1zWCg0-EfQ6q^)w8GEXNg zEx5c?az4nv#Q-&JZVL`ru_{&WywEXPy{`C}3N9lh`NNqjaj;oou>;Iwd&HthL|NsBTIkQ`4j(unBOJqo8i?J_-5tXeP z+R!#pwp3%^87V2$*s`<@sc0R$BvdNNvxaDqid2@=e2>@r{keSK%lGrc_ow&g^9S&Q z8Rv3t%l&#&Ec)2;`uEL$0&lovXl%Jd#0}shxPX8bnYge9YKZV@W6ZY85)UeWw$Vu06ynHHA` z%-9gp1q)?c$1Pi>o*5Yw5K*@(`Vr;lG_Q*WR&!t!NMIY`MO(VFs-&sy=mVFt$y-(s zVQ!~r0HyPg7+SheL6_j_b4JqZ#Wu7Z+Iw{pSr@!fCkp^93I}DVC5)go2Y?_p&)z-C zi4=RIcq3zd=V09xtcl78F8SFimEn;`1QV54$m1W6w!V#9<;b zMo3m>EySwj_S7n>)ZKPx?zFCT9!3AniITgCw=v!EJ+oM0p3*o?Z`qhWa9f`wP*k!U&); z+3Y(p(8rEPw+_C&7l#oo`bF9Px-A_g5B)^*nST-x^dT!o?{N$};JTk!`ohrP7tZ@yeZf6kl>RGOWa(?io#y@6!zg^SA+VNOEch1P!4n=x_hOKiXU?#?~GqWB|^73D7jC^;> zcXO=YGVc{_HSCL4^TLKSw}FG>H1td6*hX>Q*|KAznAMqa^7zk@3Id4MW5Os1cU7MC ziC=B~7@0<2XA;byF|#9>{ZpBsE4Un@;c$2pscIn5n(M#PrqPjNt9u0u;XdZRuJ>C4s zNyb+Ug29ocHgZBw>WTxY4wLUtx^8zw%XPPO%Q`7v{^xcjqmSB7UMAnKPc|+6dK8qj zFw=;38QA$Ljzoulbs6|tw&clo-`b_GZQh*gFU#q;2G>40Bz;Jpon&*Y=c7-D-WLB3 zih|@2*>=4&74h*}_q1eyX&vCT(Hg`s8NjP(*t2w}o%zqHJ~b~%piOHb#z!Gf^QTS zP>#zq7&XN^^%6#(&kriBI%7T+nQOf$ra3^uIa$w76z!3|LHERSs-U3nd-v6#lHCQ0_Z5Rye`3o^zP6+1AYZ&71M zbkMUGmrX>|pBcb&<=9OcL(F}X(9y*CNZ%1Nq(xqNBb?TUx zk$lXO4E`RHs)guFFugT~&lFrcRb^`BZGL({k4UJmvMW&l;gZQGulAnlKlRXKkzuO!!pzk) z@LwpCqJK7gXg^*r-tuZ=XwPj}?zlz0sj`pFcJy-Ar&E}G{7~?Pzb7j!3Fl1L2jp^z z`%lv?%qo*Dr8fq})Hwc0>B%0hT(wLv`a;DiM+c4mtk{xPR zfK4ev+I}7weaJ}texrn*7WdrG@P!^<{3J0oy)L?lSkWrmG+hK`hp0_*2)0!3OZs>q zEPXG2y`+|bGq^=ZiwyX+>Axs;Xpv#rt`jJ~slze*BxBc0jl*o0dDs=rRsTARCIKq8`{0Mh1|y`P0vG;Ta@qp^Qd|#l0!JuSqP?^VL?DJMsJKQ z&7gB56Gv{=?wdT|O?q+q-LB z53GG`%0X>>pwpBI=|xTN#Nk6Rckev$aB#Om9z9OgU3=Q+n$aeo+W%k>Ud1whyJt z7W^3^(#`OuvExJkd<^2+K_NDI&**R8{}yP?PDfTmhq1Q!@lY-W--RSWDy1S!jzqOC z@<$-+lxDPm1;%t$?OVZegcuW3wvG#}d~8?hCQ*eJ?4Ndt9=>dp%O1wGB6=c@4G|yW zOZ}Onn$2m`_k?-V;puen?PSToA=ynyp+V?N0mCs! zfY;*y=?FKU7_%3*_U8He1tg0d3`vd_>h8j!CmJCleY%P3%)PvJhi>)@ZFfAHcR1`Q z6QE1Y&%BS|1lR|y$H#DP2Y<=p+Aovv-P??7@akM}a!q2!nIlcE2ZMjf znsl38qq7fj@$R(HFIDj;vCHKE%(RFx1GrRR>x#C`uG!-yn`8z6j))@+W!L&19$sr4 zIEwca?5g>&En+j0m6|d4Jom$3CLEPFUzDd@pRqWU_jf)ID4={94mM*`6%XZ8yMWz^ zxK|wV0tZpZm$b;2_Rp7%&6hu$uh^Wg{3>5{A)l&nQp4h;mj6ke*pqr^PZ~6zG<A8fti27n%Dw!;n@PsSfaI?bmDYDDsQXx!vGFdx&V;SUVvTfR+Lka#v#Vi z;Pa-ZrD*6f5~SvR8pVz(A^0pRaf3eE9UvZ|0tFOmpbm#GKUozrW^2VPc1n4Rx_NlqpfmU*{0wn|zgJ_u5 z07a09YU?WPI#imHvGw(<()npqc^$kY`!vo@=?Hh{0iXbQ@EfM0{0DAJ*j5Sml7@r} zd{oad!z0l)0OOP^iByC@5(B%O4#R*UwzuJs*16KBt4YahVq0@Cy38&dpvZB-QCc)s zUH;D~-j|6D=d2pf*zi&Jg1!5NYJH`JQA!zg`9x+5x&%WIT#vw@5$6fYF(5?WuD0T z^B9VdVT*3a{5%upB#kSpfv?x74ezuLa3@BEAGob+60d_saTpdGOF;mMcLnYHdx1!; zRn#YOmu50b`wg`3MXUUL1|JrjTfu}s=>T2MstzhOtmxdtBKN~2)wBF6U|s|){1ThB zzyx~JSePNU$WpuKa`n4^d6ZjSb;ecsGv*I&U!c;#E56Df1_h7GWNy)%IzmpoR9Sne zDpLYGrbU_)u?~S0rzvkYQ*bOE<|E^prc!OM;<-S}x^%Y^>CdK14BLbv==>`7G{4%? zph0|7!-7bCrGEWghLxzK^{11zr6QD1`IJfC$_0m#R!!t;1$hyiTb#VU^Aj!pq0}Uo z{DH?*zet`!ZsNU_l1Vp)-RfWgM6g?K_ZuKhD9882dKjWM=}g~(xJ@a=O_8L^fhuwV zAUZ0ZCfGrkgfdJ*GsJB^vwnF1MtQg4+NU8#G@kcnI!bRcEHLE)fM^9z2 ziNi;Tsi0YRrhxe{pjq@TzWz=szu?Hj06YD=5bqAwt^8Q09Aa|spO5}{5adUTxg49KibE_krGZLKz4^Axk z{=cOF@eEw|=@o9=Z6+G4!w2hpt_Pfst0GF7R1Kg0Ec@;4zl-0SUs??Pxi!tffDi6O zeVfE_ZhZsy*t2hL92EfUUg2=_*50Q2cU@VdYrGvQ=%v<2O!wa3pqF3vnCp<%*M{LY zf-gTlCH3CE@%bfB&Yncqglvv49UptMZt6Mj0zLX0-t%ruBUF!y-@f=mcj6`o>vvRt zRlA6Z-?EftQ@UvD|LSk4u)uR&+>c0MjJWT}-Fv_1rtJ*QM^m=n1(jIeCWy+nIWjkW zJR8%in;)aHeA_p407PwT zcl0NUZPt62ZPpq^2^VI=KvEm9+id2sP5m}s(6tcMR2A6U*uGlD$X@NNKXGagPKN&P z;+Mzwik@nh%ClTDRA(#e13sHNv6MtP&Fa+uz?cn+MHf_9pX?8GoRxtw;WY`#SddNS zW<=`LeJod!S#VpvB4CTG@C~RHF}zIWlft{lor!o9w~)#(MN0vP-o*6VPEe=$sw!GS z>LrLY5DqX9RRW-+&F9#*fA%#|tZQWVUOqL~d!3>MCkxu-67ZAGjp4raPO_nmfKSdq z6?<)0>WZsJ9SV1K1K1IrJ@MmDtd#Ms%x~MO!Kt7>G!GoNFP1y7E&sGW?#gPCjF?+t5E!ClH5A} z6h__)upin?jY!Qrw4N(D75+w~(GhqyB_slLN$W5=+s>e`QG8P|+-I}ppKXXtT=A2h zu%LQx5tC-l~n>9Hryh zgZbw_bYJhMVN0(^15tRT#ZD*wEiZdK>tUPi_uh(rS~rf*wmjo?z;dtc-RfvCJG7%e zRUX4=Nm{Cr0=AP*>=BF01i|9Bsgjj<`=@^__<%AF7bazaE-y2~8YWEHrEu^CEt+!e z&;5y#Rek0Y@sz*jll+Rjb#G1>ds_7Wv*XVEbe?AJx`yQYfBtlRcL5N*H1R+fv+#EN z;!9iTFC{F#S>>;6cg>2*U=eLsI}rx8MVih1S1Dj^dZI2fM6yUP?VG%-y+wYKvVe_O zR)olrl@3Zd>^3EHyX3ZIorl(+) zY9`jGw?)LH1{J@k;%(=XBIgrG_((MKM;C=RmXW;WF$VLHin_{7&PI0?-K&Sv)Ry@2 zgG9Q)$8={?2Ama|j6Q?haLJoSHK6V^UM8{2*|S?aT@1*vnH)VV$WLL~%V6EQ?K_<` zAmWQJhVQ#K-mDg347mY!JA}2As99Q>sK3WT+bAf6`kh;~(x*IG(V~SK%5AsvYj_m$ zetlu*hTZk}+6`N8mYvmsy5zVIm5m*tQ|~f&4mj7ABzXH+6q~&g6#66&9-A%sxS`te zgs^yO| zB&Wtv*ZoQ6|AFFnm!}5&KR`E#zH~|771diK-K1m{;WQySN3`NO`=z3j;y2dX_H9Fd zcF5a|r5#J(TR1ka3Amzd*dWG;$Nb!bV&<48o<=yna|f(vj?+$l^;*Mxz6F)85{VrA z{wwH4v%p0I%TCr=;-0y)Dm%4}t+kp%? zAu-aQWbn*ZImHGX^@ql-s3pgJ)xckegJC$E0;>mUp zWyI$I-!_$n=`IryPLi2n+!)+kLgsH16?y`-EsB26HR=u z#uuYTXJU?j)O47)G?3;pU9|U^_FrtM&l$z-Hj#=^ef^WL!f=!vk*P_YpnzF*FY9>0pQv3yB6M)Z~}A4p@%j>0mo!HWOT0r{_;W7%*s)la_5)_11Q zj5{iBvf0=0f%1Ek?L+(LKDw;4loQ?Ko21nIDed-&F>z2bs@CFQV4BX{9m^^gjZRNe zRV{OCYIl3)Z|)~s!cCQ`M%Pik7uJlI<(MNo)CSI`9sYX=OO#G}RcBH+h;0>*=C+E( z5t~(&6E~Rew-PNCs?I9E_of`pb`M8hcdhHQ6Ay3HP)6j+$z)CTmrow4(e>{lrP>mljkh++k7d@^aDd4%-{%yfv{VJjqwui4CFB7!_iO2yWU3oVx z8SrwP1K&i-L|pzJJKi=i+4-20YWDMZ5k|T?ri+Z_h{ozUf6F$kGe^xS|MU{^)dGkd zim*kWhxVuJjA-%BrYzD`){2fDZTb_O>*u?JfQxB0egSRL>`fJq;$g`9*cer@1hE3V zo6X7VVFr~;&%QJf2LE_(J9zBPSK&|#h-am2tK2c?@mxy|X1Xa3u?efV_qG4IA)(Wb zpEW$RD6~FxV^00F+~m))d2pVKkCaRfcfU7)grfA2i=%!07ZJYIy>}KP6%$8wkqMmH zFTPgK2Mi0r`K{X2`~jmr%|uq-atyw9YB||{TxSM}!<17XQ%cI_ z#HlmM>r-$Wn4XPP#E$8PEhDv3-GUIk_I3%`m;{A%ck38@bAovK3}t58h$cK~_=}lr zgQ8RE3GSOj2IRojNOg|^Y&KW)2_k-#Pkgf_LU|_T8pN8G#1(g8G|^oG9#qMZpU^c> z-k7)_;2E@I34WUzIWCn{v9eH7G&ha4)^+K=!Ha{L;C8QxVtd^St~A{0pny?Y6SgvNoqFnjQ5&F3($U%V00+b|D1H$Xd`u2& zdObX|5BtzJe+{Bi9c8{dvnxH;mm11i(MeO1!8P%@xU`qZLy(7*IWZ0XS1(&6UPkyoW} z7D@#Q=f{K==g0lezmGlt@hn>NUyYsyr?RCJsl;!!0biSm9OkkSu&7V0d43+nbF4uC zIy-_1;KGVPiYAGRgA94ZRN94#=jYR?XsQcg=`hMTTwWewQZ=cPD&g`R{)MWE^QrVQ z1r}ESlT@}jdGfggUji>qE5E2+CLISo>a+^kND=%LQDuRYW|feq_Cjjt-qw?Aw8DEXqPmh2R}nE>BjiJr0X)pY8}3OBmQ)c^VG)FYqk&^g ztF;Z$f}fRU=V~f@YLp`&S;nenjs$i_YK#V`bixk0o~VE}L)|{lP`RsERf((K6j$}I zm7>W7(QK_E1U!)kD9W~og$2x{%kx;6X8}y97cy(AQi$n*Sj2`R>eQd-6JTDHYr(od zEpj9lj>&db*Tf0cwRW{!N@i5}oVzl~PlYy;#b{uQ0EbPehtLs{0SuG1BQki^(;CH8 z%Zg;d#j;)H4-~B(Osm`203eV)onUN-mR*ORbvP8m#qQH|_2l4f07#%G=MXKl zepAvE>t+M4&AB(i>gK{TkR+R6F0bd!CafE)nnFzO)br@CdG~ME1S&;B-zkbrC}J8< zr6LXG0A(GLsPK}&a^genfxQh|e)}6_HSK#8-CPDq(ul59pcoDtvO!=7upUUj)JG3m zR%jVCW{TAB`)ri8_x90gfTto09Ljn$kb0KzCgk`c20xZC>PH#ki5ecZ%Eq^n8UVce9p*lxh8XHK!~k zZBbHc)}068R>i-iEHsC|GsRM}E2D-_HkZehXZ3I(nhKDlXi@honBO|~+MjhBBJg1O zaM)o3?6?m`)A6S}+O?SNZkJ(*-HzG^E7$tX+LUB6R8lp?816$lP>>X6Y`Y6o4%v14ONfM z&~`M8NT!G?{)+{$XQuLhu>fkklQz{c+*+}sQU)7J97_#u7(BnUxzs$t^rG+m$ceF^ z*6ueizd{r8^8G}o$2l+<>nTMMh+A)ChzN^m1n$>|qZ_g)0x>`r79D)(Q(gbABUM%< zymuZ&Am+w`qTNl`KlF1QqBkrf0G?H+omK3-wtDg<&s$B2dK+Z{G+~rNw|JFWM@ zX**0^nFS`t^z*vDUbwuk`z&V9t)Q)78;tFI^!VPLxo;JikHS04mcWUNz_&?)xse?^ zXE?c6j*ZPInHv9G;H7p~C&5o4u6hSL>&hkMXN zcS*P#{Si^HvCnp5^!mHge!JZ^rpt*pIzn);{A*iv8aGwZ)fMoGM&X~{7qe`3f-L;a z*?wJ+4kZGE%Yr=@R`7Uz3b?{^21ow zqvy(fVn6))d@#5-Aemz0eqMro*XT>nM(LySyjI)6Pg0`~q_=F?d>fPh@&bK(e15yk zx|k!pa!CZO@Db6!6lLfYSZAA{-o&zKw?0TaL@hy-}bd$t!Qy zM1V;W(*f}RByEK;(yUzDFNfbWA1UlQ;4AUy#j4$)tcaIL;*3{5GfS*vwa4C?Gx|L< zp(uE~_MgKAk7ox?ME3m{+xaYh&6`uJ{+JI~eY5`Y;jX>X_wj3S7(k@5_={85ugO6K zKIOy`?&I^nf8tPt{q>2t3%lIY8c+v}lZfJnaN6cnSf-nfD+D+%HdadqT6u2aTcY`- ze0kp~{Msf+?Cy6i@j10s;`o5L)&_Nv=hU>oqTRZFZCtTP>D*m0>fm`z>Y6$UVC+{W zd5eRQ6_ztooUsD38{7S6%>YN|K#EuuozwGI0`xqd&J+eafL;l(9?_D4!|Xv1f_^o) zB=6AfyJMY&2B+*~gdfuq=F>VX;ZQLQ)N0?GF0pE8CeQD7s$I7{uub>YyrLjam0P&L zl6KTc?sZjQs3T6M-xG6}I96DVR8A43`#9vRwsEXA>+l%CJQ3F4ayFmkXrE0Et}@)? z_9!4%i!5BMG>UH4+$tNITdsh$yU%ssrYL0{Hxgiy_po;vfjFQ=dSCALczHv1sQ2QU zTMr)}h?^}Ih*g_+x%EYy`(GwOU)1f{|8q@()fEE^b^lWc#M4{Fa3Pd4RkC|c8q;j4 zHv-O(&^!+d;^5r)~QtphVR>RqBzEcuR1}sHqGl z&EswRX7Vhgfx_3&z&+PejP~w_L>T-wj1Gf*tOngB{zxYl)|16G&9D2r_DHIT1v7me zRKN4Q2@Gns?7_ZU`S&)v7j_pSwg4VO%OmgA^WuKI!%?_+%a~OoC;0EwWaACfEJ{up z(PmmC{-%+=g0tgCF!F%dZkuXFmYHr9x}MUGkOh7?2?v1^@g%`QBv?#&4kL;6vs0}E z33w_~UO3dZ(_(~UWQOgP+(Z%^}F3nlLCBA*!QmYPn@ z|C^9^e9%Gl`2cS9fhBu`^DYF;$4<7=rA}bzt?vu2ul-e~bva*G?T=rVzPtqa#Gt0? zEO**OmX*47ZPX*vzbu(wteu-y)MgGncd_jq$=TlyxBcNgGa(}Q(!1T6Y5PN@JaA#h zORCj0CtddD{>j@4DyXw~?MnUFJ zn#}9JLO07bE?QNsd45KH>dWWMfI+`ig|^A7idP})gPgn!A75wAk_18KhDuq764oDq zeXUe~4fWTg#2p^d`V){IvS>5*M6obu>z6BKiy#$8Ic6R-nC4*_SkA|jHc*vNhKk)+ z8{SdIJ)pvHwhX%LtD~n0PEj7eDCXi70aN~W(Mivtdi2$%#QL#CCuB$^Y~{Aqdb)P* z$Mzr5>$XEzHacxPO>!cNbOxiNmu$s)-}eD4Gt&=z;T*k+up~J8c{h}V;3P-= z8&ScEUJ6e`ANZ6m21;HI_`VsJR*pxtQ5!eWNj{+Q19lUOK%wh}^Aqc(0|H+n${$U% z0RiGNYjBCaez@>~sQOK*%}3H=iqhhm(&C5Gj?bsD<qyjS*D)-pa>Z-p7l=pIScUO?Z z*G3ti&0qSMXXX|?F>_Kh1i;AlscE^P)#|DY05jp=8bL4=j#EN128SX|K+tq!1f2h#n6q zYZoXw==#b4M3j*G;eta?NW4&4!awKuL6H`lV;Xz*o%)LFj1_3-AAW-ILBL>G=@t-@ zE{XoRgRV56x%Mjen=t0AV7G1t02l_8h1SfdNI0Kql(3v3A7SpIbWs)=XCJ*fwLOxO z6o!EZ;DdZDgM;&98Bt|R(VTJdq|`h6v!l%yR2NRmsw)p6Tr^{Tf06ea$FA z?WwfY#f@Qwm?w%Kyv5{u65x7!u?n>95IWBbJR(=v^XZJTTfr2f&MQA4Z-8d(1|%-Z zpeJA$1f5RG=GMpsg|ZzM=dC9zAl9zy-f%o;6(rD2l7!n7I9;DA7i%kaxdn-*Q8rrw zBkJO=|yat#;BAgt(w%e3k$HdvHRZmc5s73ot!2UF|js%n%+cTqr@60#_N z2ehv?SJzt?FtUkK38%jwVhK>wVawaK9A}bz-owXJTx)NLk*f50+#%Rnn zl8_kZoa(0bt%>mMj-YR<@>Fv9u(B4a69)?QG3po-6(I{c>F#$z zA&*!l^&(#xJ42DIAh(>mg4z$yE&X0K<;Zd2xnLL#w6)ObWG+0}ll`qH`+Lt-hpcF?mJ?29752lD5LCUzJTJ9#UT!isD{S$#)L zcG^TPRY`h^n4Pt&fdDmpl?OWO3-#6`x8%V$J;eBPz-sZpEc4>)mRZ_gO}ziJLbOH| zBJ;m0#Gr0outPjDWAWcdE3Ju7E<8B)+qo|2;lC-wh)R3ytjBp~7`pl@+BWN$-}5sL z`q$A8H9A^(#4YksAqXF&=UAc&v1Vg^Ku18T;K4P$jFsqUC8`ij!Zz1NR5_7vvEKIN ze7@N^a)*^RWwCi*(c8$S0g+{eIGSj--`;z6CmTSJ>iXk`tcZz+98pg^KX%AACT*D( z7qDy0FzbReb@k`xEBvnp_kVvRdh^T6tA{?Ms{H<`1={9stnj$oH1m$&Wqd!FTWXUe zY%n^9p0W&lPEa`hScf{#8W*%>3FR)A)Fa89gxfo&=77&KWX!|mc?HEgQPW> z_GQV3dIDOxd|MuJI6&(Cv4Z~Oxus{h7|PTWlq~-7-Kfp4rB!`cKxc~|7GLNnvE>0Dc8$tspFsNgCwx7QEu^=SjjeqTj^Tvg9 z$P=eF=lGa!HJoe$1TK8PC(%?&E}StY~tWF=km_d`3@Hf21vk$(DW zfAkVhYGE>n62xD-lzgRsLMT1iAqU?D*@kzMP3a$TF;c(RU6lKDW%9D_!9hxy2l;oh z4xUz{3U@<4&7ggAzr`^8ZMQQveGbU}KCYSK5PWpK-@??=;B~LELt31gxIaPSch^oz zIo-NyP_q56aC9*sc`-FFZbTEoG$p})d`j$ixZ;BfyXn+DmdBsBNJI0EdZ62m}Ly6iPVjW)6E10$Gnw*^isbK-Yy z`!y!_AasRxYOhw}Q#MYAr4EcR7`Zy&zPfR$pe(sZw;5al@lQ`}9EFv9O?0&v9SWL) z2Bo5>-K8xd$}wN9oME#Z}D^n`Wpa# zd)SlY)%7Iz%2o;}!r1U2NO|17)rlA>k3;#D&;RDEoB=76+h2t@svpSs1sn#8|h%rKl<_t zlzFMv946`^C6u^&yfQFrDbo<=@~+eOt$T}6m7eUfl^+&4yi}o<&PX7}&~o-sxx-Tx zQ!?`dMB{i#rg%@HibBEe#Ssy;Kh$VrE+ig-9Q0f-?8BqDBuZ3oY<<C()AS_Mk^H>)Mh6ue8yK4lh4*-t$$g}|tjOf`#m|NfB=sfU*u0ex zFXpDFL$a`F8qM}WJJbuTn`jU%u96bT+icsdGTuT7X@vH}3gOkc7N6X=$B|o`H`y+# zuZb`DsMe^57P8BtupC#FTa{DBC?wxJev}-I+HvQ2o?hC!-{p|ztj7{m`3etNT~;g!U_sZAh~hbXu;_?B{`;SyR+9|B2(hRW8;G)l zL(tU2U%y%{dsSX3q)YMmsq4*>B-kKXNR@5Dn_a%*v$sB@&Vh34=v3RQi;wEv#_aBD zn%f*%>1-%>$^sb^Pd;VKBpgD|9}z+XPu446YBRjA^H$_6{h+TVlGkZdvqfvKi^dd7 z@?N1|ApZoR-g6(5fFkELi|`%QY@esnfpT#&rj-7CB&>lFCJFYsIOy1U<#epasrzhU zVb=1nwlSD>G>Kmq#UKvlf<0~%dyf$fMA9fAT7O;;lJ{QAPJ$w9uJI#SGXKnpOqp1t zXY0+E=hrYhhcG3+PX4!WoA|gBaLl3ELq3`brtc#yA`1TaY|M!%Btp^eSjt3#hy+0! zrOzU`a0C~%c>}ox>ztlkm2f0;G!@5>u)3+GV(+!W+0p`~+`Fh%x@M+6*TPHSqNtD} zA5vjqo+obL-$WW>k~^R5_vS{P*^SXa;dE^1BA>F>ALu@jNUTH-{Lm3!N79@!f;?_ziSa3QklRW`Sm&aexGkqbXn@&^r ze)x#l&WtqH_a~=_K?peyh=1aX%cvuQXmGNIbgbhTYU7)5q~<4Vv0@#Q>+=F z6 zOI0|aO#WP%;_Wi!;WE|5GOA*^hGn@{K)Fs_x!$>QgWKhX!{sX%%V~-grk4K=lD}9% zSFE(RtW=02rV1nzS(U#xZAIB@1%gV(V&z7~DqqX0&5BhXw~6lI+nvMFAy8O~1qEAP z42gqayNjU#7sJk7RN!JznBCm2O0@b;6acMh2#vMXP`o`2R#1mE0nnt8SaI7?mUb2! zT$pzJfRfr3XVAzGMwj*u#Z_jAkbaCx2}dbHDp86Khzv1pm{Mt}`;M;mi(cnpUpF;F z(V)V~0kvtY+8^G!(yb+cv5ffnEud6Y>}U``!($Q8&uCmzyc85pyq*b)>I!RTDHj0H zXA>~f@E0G;%vp+o7W}n^Tv(vuI9A6CsQIZ~-B@QC^qqp9Y>SwIQP(x8FKsxM`f41_ z%Ec^*q1EMn^=H-P4{?{?GJqc2rGkNe+744R3i^@?XSvAHMBp@?shVr=0&1b@YdT5d z5@w+Lqf7%8cp8#5Wlh=AD4}Fa$Dz1pmhK2P+bf|9ydN+;W z(4<$J3JSQIvpX-#6mM@FUJ+DI(Pe;$0qBAQaxxf-K(TflJe>+I@U_>eUo9}W^dVD{ zs0kzo@Y}iGiRQ~pJGW`v<#{uh*`RA*+~r=Idi!#bA|<3?MFHYKVPmh z(JY&Vw}emprr&b8(;)Y{q1(sQpcMntG2#3ZYZ7pt0JjNE>RHf5nqE?Lob#oIAG@v^ zt#GVX%+8TE3Vs|Czkzd9NoyXPuc0W&^2~AYW!E&ji2}3%#PN zE!4y40|4bG4g?|#_19#JYm}0aSKbcWMk(m+w$GAd{_x$2IAUZbkmAA+9o9h?Cwsdv zWiWdK3=MRlCd7%7?s%^a-3HW}n!xSp(^VpNkQ5!l+dUMwgX9J-a(HbE9hI9zsvu^S z)J!EjQyFl3dti^GTTkVMUgYZCp0qk7LWJ)a_o%7l(QRvqBE;`MdJH4L8okpF`2X-2 zMq5p5;2%=mc^BHU{%Z>DmMn$w9jyLVxtv1xl(=2jaWgQd?0#r(dcHsAOQOgPx5j^Y z3_a}+Pkrh$3L2F5ZF8b-$`Lk%Kdx)Mv`nNQ-Z$LnE<>{k7-t0TxbpgD_`BPitQGc{d4J-A2<>6uN0c*U+rIK-hzJRP>(@bG+B(>K!1qA`E>?0M}8oES$ef%!|ldT z&sI|2jnoz$N(I+K9w^Rdo_XVs-PQ6!Tbr6q--?i+Llgh<7<%J%Pjyh8mwdYVbghn01|9Be`!>=aGc~0?dGqh_yTAs0 zMraUOtKXpfI#-|A45Qr;NyxwM<%Bu`iC|SP;G0NnZp>RJJQc|%`Pa8S&4BA?`_R2$%C8+Zv80<((IudZx>*EX-6sL$;Uq$~UNI z@>Rf;aN5gicF;19J%j*QHE1451S_Xe0|oAw_0kYUukveq*Q{5}NvgXQUL+hep)0G4 z(OR$w>+=^FG=eUQ_f#3kn38YKJO3tUa_Y{s0nX@fo$SMk)tF?u3rX_uz_$l~6WJYd z-Zk}UPz(99{+;$5*>7z~Ue&qSCl?>~w=N+tALBYNNL8e!EzQVo3VLEs1b4sp^L!fS zx3<%|N`~A0=`$r~F2ya5+H%aPd`txM$%v<;Rat5YLF;MWZI{GhuS2FTMmJn$FA|te zes2q&6Hl-4#y#<;P2e#yB?bNK=6!vq>L0GOLiu%T&5Zl}KF9ajX7oI9^z}^;_Btur z5a|~z7X_NT&ik%Wo*T=SORmcS7a#ZMTYayvukx-$iT5S9s4gUULsG?X!L>UfHDA|U zT^!6isy~`_xQB3m@ zZ9PgnY+kB7I+o#i%Xewc40lK|r}macro=%*aRmSe933@fXEIVl>6BaYC)LjFKA=@jw%bsjYH@i~9-HB;@RIJZ>rjd% z$B)iva&v>$`Q?TmkPyCg_!D#8l*13%2OcQ|S)9)DG#v0$DRk{k@->ngM`H&RM3 z>xc#k>;WO7rFUohs`HS?q>h{W1U=!zc1?eo8eWQfxzkEsNtWS+DaJ`U**Jb?y?*pr zt`TEYWP3L(mCe8zqL~oJyUnBpVc&O}IE&5Cw7Xd$vn^njo`Xj0_>-wCv26MM>9E}| z2KFxw?6V-zr9?Kah-s2iwO8m_{XyZpk68QpIwD`?g_{u3-siaghgfJLo5L|xZZ{-b zl+fkQQ8%ZfP`_O@j_Z9glg1;d_|h6@DM>OmY*bQ7{F5{4JgBvImuPr|*>C76z+`wW z6Y1UJd07dKz84cRFrF6Qv-a2YUD%ZVQl^Rhv@~Q~gvqrZ$wo|8>OHSHc^Ljbk4XQ& z^%yMYng>vip?dv4lmAx#o@X8^N+6`pL_K7@8aA8 zK<2Rt8w9Y@JfG;vOO)&V|H-eL@1W(@XYbkYPVx18r+Hs}ZglTE)wjPK$d~GERiCRX z{&sMBgVw!=pc`^NpOvMW*lbnpcPHqvxD`eGQ-OCgz`jJuVsj_hmzQ^s~2G0n_k zV092kDCQ>5C;iILJ0Xn$1+E2|fo{I5v0=ECk{l9?pBGgmUj{!+G=4@;fote{;qR%K z7?Tx}2WjBaD|@M>eQYUKlG4{2WDS+C?r^J8C4Ad{ONBJ44mKp3i%(NKJd+#$BS}q) z?RaeXopVf+$Bj)Edq!AKd+yz60qjD;+M7>E2T*?d2`b+V`&3ir)Q*Qd@u-n_RF7O> zTI!kMH5>DDEoYg)`eTx~EE|wVjLfdc==xL@hUu|JhgKBzSa%~6cXeeF zvBdo2JWlgP0_o;87j0F!FZy4nAS`uX)fEhMQ6zkB9eB-xg#UhNwRwl<@4y)KP6Cbhdglv=U7l=Yqk zQY1x}RPqWn$6Zy+E#Gfd3tSia+L!6mJCJ3gvRcJWegDQMT6OnTzx}hVDUf9^G}YR; zcOL>zAYdj2ce;#2+g4bz1D54qGPGQ(pb}c(w8sXWVvxExl;?iYERy zmGX;aZulg^049xekMVGS2n&cQnRh|KhXAk6hS5_`pN3;b0^ChDxl%6hz7F!7itJ+|XQhojW|H&}cy@qttCe!h1@rW9 z;C41b2e`r^L$cqh0}Keg0`+|f9|kz%U4gxak)>H*%Cm3=AXosYEh%B`TNL8^!vKFsIgeOh{9%3~fsW+(352V)QcR)Vh%R=VK@`6Ri)K!9bd;da~^CWOH6% zFCAjD`lxoJ9H}T%{$m>5*A3SGOHW(du7UubDD)_n_ZV)>_-9XBr}>87#0`VZ8zkXO zW9>{+r%dzEOv~KN!_Ar26PY%fnPlNCd+n@aPFcr8vmA4?PBv$qn#gk5%%Uish$Onj z(!*6@*f_uqN^8>zs0VeRoj|rAA^W0s_GRI0=(xQKdFV{aS#2zlXeJd1?jeBEOgt|D zgfg;ma+n(oxCD`kn!?SpOvT;U;ViZ@eU$5ca8VHWO1c08aJg4Fp@b?#g3rL>*63V? zeR)V#i`@CN@QG}$*SU8->u<33grx5Ws94r=ETI@4UkD!1VuzD&UHhC+o1pFkz z(6wv|L|}q=eTyhELCq^=%EhjQh4KKsyA}D3efiB!_}DcpKt!rTIBs{G(HWmo0N`X? ze%0=oawWg7FNga~LEgNg!lOU)^=Jxwp5n7h+XJshyjcM%61Y+if?LhmxY%2ZS8xhH z;1BG93xr%gI~bmccA!G{J#Y!oJS0`H?RzW#^PR6fIE6<@&td>1gV3s04gq6md@PW3 z5f1|1CMvxBcev1)v_2UBlwz71RBeX4lYw+2=)whTNyp5Y3H(f)kq+34#oTJ9+)gN! zkPqA??6IYzA)g(_{Bz_&Zo4*s&f|-(bH{zmEuKD9$~kw(E&Dc%z`ch6Kr3XFLhDoH z^4uROzH|gXltSR9a_!71hP2$_Uo7T|GZ@jvq8I=LOtn@8k1>ScAbOk_{Ndp~rNae# zw{n`DK%p(1E;KC1;5Cs3%S;PZ$oTD>cPc8&IL?%+5bo8y<=!bQdZ=>)669HCBr$q`vPgX1}mc5B9dfpEdCz_L#I9?xpu->n6){i3c@_#s^tS7!SN{ zbZ!v&LArb(yJqR!R+UA6gyb>YFBTjd$R@UhTOkl0Kxq9DD03gYQF&lj^8SuU^=pPs z4REp=5r_bYY}*WpZE7wIYPC}$4(3FOy~|nfivrwfS1urdKmfwo!2-GYIfS7UhJ`0+ zYkKQd9_99D7&e`Mp22-n8{Fr9finbDuF4g!qNEDv$bo1opwkkW8r?X8@wu?&rzA)qh5-N3)cxjj{!1FY%EKZqoT2@{4|;c; z9&Liw<&R`)yijo{WTrDe-O;(c^r>Q7eyD5m5Nrtl=t}BH^Yy-I-;XsrA4NEKSM%|qE74oT2LRMot0VmbJRBRM>DYU?a|+x zy`x}PgeX*%U(kuFzs7u+&y5~|s?4*24Id5Qd*6IIr*_Fwlf4C~9euowgd43i}OktI#eQ)!8xEr?i4px-QeKmH;6R|1O!f$Z#Tb$5=1 zKwEHP(j;sMb<_j{7sFHI;6_`gL$1XtDcwBzR?98s#UVR}I6pG59SK3%bzpE{hHlPl zx8w$Jn_m+m6&y=dTB_xM_shnt53Jg%!V3u&fVd_2_0ecC10`fv9%KQthqi`qeU%ha zshhc(BnoxtM?QrACbq-^Je*TeqJCpm=b!qu&X{rFF+@(od^F*1!JL49psR-QXjk2K zY3`h1s0x9K3f5Y7wmPOY6)hsqNhK-#BsbvgvOf`s+K=k;q``lnICC%!o0EcCQ-@{-JtTnAGX_-D9QCOE4hBMCE+N z#gYxMx8WU*H5v;)i)Fs9#Fp27)<@MSe48qa`z`;1z3iQAU%6p`LO#OUen91UE14vQ z9%t@tLh@j$7h2E$G>P(7zP)xW<@YKL8O|37@7vyiU~&5O>-XPsUlC?pdFuV~9Z4(S zyZWW{^s0>BZU_O!gV2gRt@|@ymGq;r>UMbiBkai2wT)XdBT0wuF0dukQlJikZj*t^Z2JSm8i0x=W#yJ5H zU`>lH1CqhyrdZBXtXSzy@u*|Pe0P0_9PFa0Uw6aQ=+`6Mxh~{%YGBkjWojfiKRQn}c)P-lEHDHfjs-K;5|$PzK{AWkuAPh!Xq z-tO{R6qk-C$JH?cUtwV*44}wdJR}1w88_+asF@$e0(_MeO;SL6+&-9$;7evy#bXBb2(s7CJ~Oav(&l zBJ?2LfnF+m;v*9RiyEiCKRDfdWhHOc$;`+e4;U)Y2+2fai?yi1V3BIjF| z0Mx&Jlt>zRPErUPO-=O^gw2ZU?D=G;d=19o0K8YV`v1wy+J8K1_sxLaM{0tzUrf&Z zpE+t5jy(9k@u;oYXQVla<9zpuBx$2ct8IUFh_Xwtud{C$op=o~)6Uhx~CQ zNrGLG&HaQQsPW?=RCblWr3Sy-lgN8f1sv9U*>!*h2-o}f;>IxKjZSe=9^Ki z?}TTI?lR_Xr1EL8(`>Rd^By`$T+d4y9HdaQ>B)GSOdya63 zU@6(KoOW%}9cM^|n@RV9@-k7j%FF>ht?(D|658wz3MPs*qgaBLB;ZQL%5ilI4<9!n zK$L0HhkX0}3+>!tm_~^)6li={6S@qMKo1ApQ&qU$%f#xYC?Y6ExjcxS)&)cIJ9hB6 zK!xW4$~%!w&7pM-D(#}kAl>Ju$5C;>gXJMo2X@OSkZHWkA~wBR7#AG;o^1Wz7HnKn zRSz0CaSyTocl9B@4~~nka&&>YJX$ z`W5O=FzYAe8<9di<gdb9>>JFrutSG2%(!uy3T5V!#sQs_f1M%66BeBis*YTI-< zq=-k+^bE=Rwo^N!;EKeRsMgJeAhb6PJ1t+4xIVo5dmE})2~pu%RHP#n9YS@IWQVs0 z3a(uP(dg%~R30rFpCb)wHw)#^M4D(~<1~p48bK&hN-I*vF;XrhQXwZ&sVP!rJaXSg zBvB|zO)E;nG3r1_lvYlZPE(ZLc+`X!Mid>*;zyfF!b1tJ2k35jlHsV)3li-@7DBFS zL>P>4WcY`&Uppc{-J9PC4;zU=yRpN-7?x%XGRU1N2+&!$WfJ)E5nN3GU`=TrIRLs_ z#(wvTz5Wn)^fgWd1g;dyye`Cz9t1zu0x+`CR*?5)t=N@auh=PRu#_Q?)P*~BA|?e7 zbu-!X@wnTs;zMgO_LecIIwbQT-1stR1qfPDxZsio-!8@#JH`q!FThwhT`~Y&;%7-3 zsO8XULEu6lcx5BLR10ML5den;!s{^5BQ=2t$QS-GsvRL8n127Im%bH(!#g9M(u z0=6Fnae)bwTCqtajF*q7Yl+k$0fg@|iUb1Cd7@uiN&{AA}^@98C{00C*i5E{)qE3ZL^m6|k zNml#hcKh-V@!lQ0rFCI(vhSh%p_`__+w_NJ$KX%G^lij_`@Y3q| z;L)D%Vo8s#!t<4T_oX*oU;3ozT65~Xp)r^JlLDKkEtmSUmajb~eS$#3%++7J;V_Ch zJN(r~`*hFwJ5R6Aa+lNlZSGu+T>33;{C=Ya`o6nSxBTB-T7R!UwEVaCL~J)?ewB8+ zR$s_(;=DBW>JDjBxWko7h*fa6L0mSwb#9s3bBhl(nNEV0ux=C^Y%`}P|F)etrZtYI zMT;%2PsN)G_|BNi9;XRk`9M2p3n(cBvH>*KQCzqhZT)ZCDGFd4NKXleSu2!Yw76Gs zFYi#nxQxN_PG=yCd z&%$ed|K1+PoIWtxbv%GbZr9%IItmsix-YG~IN;{|u5D@A<4(#>bs->O7+4fLY*>|U z&J71YrRi)iqwdhXI+lLCB0SD@x{?{$^Fe=gX3~q#;1St`L;KMP+!0}okPPQpRezvQ zZv47tYOmgRK6;z-G;Jujw}=5CFuTlkXxxfm46OTGO&Z2(fh6%Bm94euH2H*yfeV7E zY43Hu8+8H+eCk%Jx}JG{z{od`J&p0YBV3tO(l?z$Mq*fBnuhc3FYix_klPLK|6Yv; zf=ahksn`7G#j*_RuxQUJ2H zV|A%hZ+qg~-R7l0_ePkct@#@hmx$~A$q`>pNS zbmc6K=IIcwvGAqgP`fBg7yug52`KsT)Ttd9e342c3A8f=_5BXA~!>Q)j1=U}@?XVggl~g&s1^1Q3O0dj+IL zdg9RnY--6wi4vjH1H~dwh0wG5%PFaqk{$J==Y3hGdqa>66Iw6(Y|3dRynX&a-XU-_%`^k7133_+q?UXRVH&Qtc^kHPL@^tv+Y4`pm%>6GLHZ4-2{O`&d}LeVMoRsQj1D0s9wk zU(adcYf|p}dt1GGyZd&np=t1bz?J{_&KFs4>ivJ}o!|XUl}*oPS7%@Q)+LgL(oI+A zB|04TyYt$f0apv-974d4+R&+Xw^(Z_ph!X0IegS0L?cJ4l&tDJyG&7OI_LUp!9p8$ zb}A})DoFR+7sIx6ko`tRTCf>HKBvxA3KPvy_5)#heA5Nh7X0iudM?3m(otT)B9B{Q|_tb(FJ|cAyBLOOb8xBJdrgVoQ*XoL|n#D@B2C{+2 z3a=tq%DhPTX(v+?ybp$I_v6XogX1A|x;m9KP=AOalA%Vw&_@a*f;wV99+U*QiR^6J z{%Xm1F+SAL&^Y)tAbk5Ble@90=g7BU#Q4iOo5q$mgWoPc*?!MTZET%C@;&U`_J@t3 z#E*AVo^LB${LmWl6JE{E19%UXkxLHWKKxUfU+GBE zF)USy^z16-&~H(zwbRuKeznK{F~}(M;KSHS^S_=&{NDL>t6O=d_Sy9$uGOFAX59On znMy7LO{(vzf*<UeV@DmlFLige zF=}IB`o*g%SJ%g(H|HOetva_)f7HIb^tNIC`!P+K?UnEB31ImlcN6kfVKNoO$M5h9;kRZ+gYZ9V7=;*DVG59R8?{hxo zWz6Yopnz69PcdMR)5tgZ(S3 zTu1?C`95qMi?1v|q8!o!DkZ;q-D&kA(1^D#t$= zwQC)P1NCDSI&<%@>7HC*u4r7aqp>gqNPx}*888l}!|LQV*q-s3dts1xYy%ztcv;oT z&r)a4V$&PkoBM}>dqUkRsX>wO$s$TrOV8Ta8~rLQok|eH2*%ecOZ{c0C%_?^+p8fr z??k}?A?<7Z4biYuWOkKTh2tv%q@d7!(THex^X?=sN};z1eE_=1{R_?L(5L>kE6>&U$GQ;6bNa79IG;32}DGQhawpo}=4x^!}nfm+&YC zFr{Nj5y0#ot6Bp3uOQs-q6KX%yhTn%`PT2&(yH;?tsT ziH=UW8A!+&4l#!eQ4)$#yBl-7ZS{^|;(&^LgKpafir5Kqx^YGcnZbV)IW!wfACw~B zzGxQe$;-h$2uEo)4Hki16=9VmtAuKngfYYbz|_A47*R(Np`Wd=_L(JP2=OYw_#H{< zWx>84PBy2aE9j1nsOaaCRTzfp)&8-cOI-xBONaQ|-i%c$SzJQfVT~S%D9drplp|qP z4n2oo*XRAL_Bm2@au0i|rGnf2z!YT|4VsvgF|P?Z{c0ba9?R0caKa_N!*zAbMta2h zRP3|bg$z9`SRa@-*xnqbaz83$JF;Lbx-}AS^QhS9L|W0D z@I9_RuP|vVZ%L_W-U|UHz&AIX!9^p{l^k_m^a_r4Y+4*yVFu(8Kw@h%KfI!fv@mjp zOTbeMr7d(=3Q|>y*v2^Cl#>u-josl02VmqlresJfSNB-$a0Jbm1G+M1ne; z)G>8i`0WU}dv8D4G%^ClJw`!mzCOaGMRBX(D0-AhJH6r+r?Wz(n+bs#9fc5a*6=!1oB_{jLEJ*GA! z%Lm!)#Tb&OGc36!mH^X;H{l7V#~$c~aruD$15d5b>F`YpWnf4cDSD*V5)-A~WYSkf zURF-(RXKlZ>H&(xV9Deo;5^m56Oe#{q=g(?(IWv;;a+z%u zXs!SOvX4WLG@&!)Q?U^HYAOyAZa&4!+!W$B+$t@1Pb{-T;`A_fMllH*a@kM~y1INi zYEMObjEDhzb6P-CK=`D-);B0Q{64TWj2dc^$&g_YNd(2`G@kgS z$;0d9i2n9ci94W}G0}tGg`m*}kguD@2OkOS1Ugyjwy6UX(+sw)9g})E*ow|Lw)W)7%?Q=`lYSj%7>`oo=cp8Q4psgF);Dxw^yuA{Hn@j z2ZIZXzTL*1+f1k~e!&D1y@)*qi<3tyM|bimfW+SNT}9M^-H;Yyqt+|!wW*U+3uhm+ zb*~QBx_xp?GuST#y@d6ce;!NYQPYOAd|+hS87KjST{bts8M>NOtADB$^ok`}7FPu% zE-jX*_N-a|vL(PDL0mFkK36>??U4;>5StEUqRj=cHXo z#u;9|eu04qFQphkkJJ%^ZGI{l4Mnu4&cMu%iBncd&7z=osq7+DO zI9v|tU~l%mzv}jdllY2-EYzL=V*%03caFf!T`950QG51VQblWPQIc3i_8_{b!H{ZN z^jB6A_l5UDY`z&s6u%u+3KsmHXl~H(OFGpTFu@fci#puE;L-p{syniem($bYC^DrA zX7yG2UwxcqPo>XD_yPy1lE`yBBrY~Ej$HxJxHr~=_C_@j;qi(kT{oTw$~F!NycZHHnfid ziDU-S(xLJMrZ8{4yrAsZ{H~@8`^qigy(K5wJt|UUtWal!iuv?d^Xd$ENP~K7axI8E z6iMM*uVx^A7uk9RsAtOdWs03-Mp9k8&GWD^hYgEf-n{mS{{Raxd3b1l!%ykdYtSGO zqE_dq=Oeh-dtSrs`4?%WZiJ!@Zf@=l2*ZAeP_~trj8Xe5CR1Ia5c^8|RWl|;@=H~( zJ)0PcO!bzU6N84zolqngXC%MV+bwstUlu%vbARZV0UZ1lmJV$POvP72zMS|jr4*Kz zNT?U;C1TuDv>_o*(7LS3MHM(H{7vp{%h|ZKlMb{c2g%q;Z@f4g1|yUx_>gqp4|j<^ zW28hs4O!uEm^#$IER@GwjAIS!2V->4{zEdWFxkRjQpcJ>u(r zBM(Ucw9KaNAhFJNSDmFl@no}`cG&aBBV)?gWtuPc!@~qu?uscT9BO6sx+7Sn068JU zeybx3tao|#HBKu1@;ZtK~9W&rXB$Msq5zC{3?g;>4TD-KPBR@k7 zI0#Jb?)T!e1h3iAHC>Gfd(T)3e=!0l&&ixdZtndW}B=1Aw9zz@JN7#AY9o77FDYiAuL zkgnAgP-Fd)XIRokEHfR;R|$18PmGT!bSTQbk9kzu-ilO=kvVl5yrAkiUObnm-bTt5 zh>GHNNw{RLqwTIsT7b|PJe~~qP=g)Vr0ElpM6oGf9-H2%>Q0J$!;ILytP9x7=KPu%35t@NJ<_8 zqDUEJ0a?dpBVEH6>R^4$J^O8`B3aEtiEZzqeewwxYBrP7~m zP2`3e1p7p!6ZZT9H1=8ab1Xu+rC%mj40oo#pP>6IEo=)?RbO6bYj;xcqE4=Ry70(- zZRFh>ZU4dH)LV;Cm17PIniON2%e*}Gw$Ul6HCiWIq*ScztQkn?MR}N`pP{db<7q-# z4tTArWAl9Gx9Hz%Q3j)5DpkH~cUEQU#<=_|@ z909ljwBk4<;}Ah{Vj;@20z6#3VD55U?ZdsOBJO82r`3^oo?SQnbpn{O5O0_b(tYAZ z;nGkEPK5|xi2gVBm4KJl0Xv7p<1j?!c%m3=Z;enAXOJK~D3P~4v3?_t7UFki9Bj%- zD)vd@Sx#a!U4QDB)asbr?+6}jNPcdalrW$CQY&T5G39kg%6Lx7+oqJs@stl6DNLc% zPglNBH#3}aZ-(aPhoV%&;ZVg$sf zlgL)c?V4Ubox;BX*_*d5cFFNmhlG0=`FAG7W`%_p6(!P}3s}N;R%3mkeFRqdNgXYF*gEGeP-Cc0nPKcZq5q6;eonrEo14LgR60qk_>U{1b&DIX9#c z9c2nQM96`HUEIQlBScQ}o&%vKs9Y5PVVAjP9U0sq!jb}&Mx+W6{kaNSQM}8S>b!YU8X~0J zl!M6N5D3f=z{o(L#>v5T{%&O>Z6A$eLiUR8Wfx``r>cXi1@93H-T*LQ zS1RE*f%6%?bPy(76nYOv;5;S|-X()&i(qn|m!{D@f}2nLl-71&K#wCXQ3y9;nYY6T zL8Wu}9LM*e?rF56Ix6uU{a$NvxHYgCQB(~hVqKc=W_(7D9p@HM0>5nCeae5&x!pMH zrMq_vJYE%t4a&K}6iVF4jTHnw*9M?eae*UMZF#4@Z}E)Xq>2}n*wmJhH9^jteSEjP ze${%g+11^0!VXJ#eEnP5LDa7_>imnv^Tiglbj- zD?sk}#PfC2 zk(z263gPw`wTwhcvelnG=d{lAYa8#&fwEy3D~JN}^mg^_p=i`IU^k*69Gv| z_+NkBe&2j7G7oR%0N$q5%A_k=#K<9+pXgih76<|FcS}}~zSrt*R=Y5mgg?#$d>d&dOmUbKI`*kX2aLF{m?lsUQ8646Rx^W6hs)YiKE1eDA%-1pH7{=%qK3!}6hAp>|h7-Rv}JL$KUV z7(Mz@9aczGXsi$wl8yhO@>oAv*}GBjNFkEv9C-93h`TC~!t6#E6`c{1wsGjJJYdxS^os+I%& zWoSD37;`j>i1vEQui3;7qq5nMP?k@{z4spY$nz#}xeMOTcAE0?Gz^(C_eOgY9RhF{ z7QRN*ab2OjI`76Ad{fX5J^s{gFg&Ht4CHuq81+0!GRTTQ{s^d&&3$&!6|U<07oqkk zL~`?a9^h6H;|!`vxjV8BnaI0b0vB8GKo0MeaS1xo-i$e#o&MU8>XUI=z$E0| zZR=qxm3N4`k&1*4F3C$gT@jadmwONTWzTyL-GaUQn$JIX^}|tG*W#eSt@j^H+dr_b z@=(dlk)?U`!^GmnBp;*;&Yi2 zxHctJFeTD9#Zz!w?DrHw;**pFS;F9x+_g^%1)q42eqt|XDqX`{)QW76eB57y*E>DE zx2R7mfalrMX@{V}wzHpvsl2IE(~_!>%nN1?x6Nz>sb!3&uS^tpMDZ(4)a~BLVNVbx z1jAsAS(gGmM7kd3+w5tVIZvB8gk+Aq;%t0LzO~J?^*6A)IDV7@HlGDs^Jg}o6cq&w ztHK?;$K8ZrDsaoObhr$6eY$41K3ZQ(PO?Lge?|rCf$oqyu7_%O4FcGE5N$ zb+{l+5cjfh1xr(b)AsY{#TVCPc?9W^(smX`s(J%v%^idbx+%TVF!c8o1Zw-v}# z+*qmDi2t~WNMC~uZNgZ6MzE~{SMZ+U$E(AV|gkO!ms|BPqP6GqW-x9DBe5l*>#t^$0qR~ z`853Nfxmkwl+Hx`eviKq|COhef9!epcRtPP(m2o};_&HD59MR-H3+W2xfa#q0k>{G z(qsfoMS~Jn1=gGH#r?u2Zjj7*VgC8wGUrK;ColJY{cHl|)4KmM`q{UJ3I7SnoF@Mw za~jjm4*XN*ocxE(`9{2ObLIb{%z2>cwm$d&EOYvNI?;4@V=_VIb(vJaZ)z!8&~Ly; zTF}XJ^iyi_Q;di1^N36n?!BP4Cx=0x9V*Q_c&-HEIUY?#r1~N=0jNdCxakBZMTs1l z8K23?&=>a7<`}~>l>K>RIQDn4q>_vt@O91IzS1w11d}g^#pHORMRIas`41T?yE1tT zq~!=T3kj-X=|XA3)(wC?V5g#_F#p^0;j$yN#9_nOwv{xURVjt<`qfL5N%db_>kDmZfbhyEy+P$T7!MXL1&y-@%4!WS{1 z_vIKAzKa?zTc4b^HNgIGdMsIG)ajP*O} z!+KjwQ8g_~?jq0YR*(DNO#I8JuexHH^=im)0z>Zr;k6@!hRfs9f%>qEM@bkQKw&rB zrCSBGeBsdzY86=L6zHxuikIuz8C%6cLo2Wjcy;R5a2e|nI~2Y%1*n*MhBVP|bn6wa zE^kX^?L^@Lenwfz+jl|wJB0fhu-7bvt>LfI@Gsm5BCK0w zl9-9(Nc&fwi}WYo)He=EbHT+*YCmgxh^#I4D#z53?B2deHTe8nof`?15}_f6vGS*D zPJyas?1%{FMyE^E?XZ;vw(L(NZ?zAq%`eY9G`_i)(T;4@K4TQaOQEy_fD8lO@2Rfk z9+Tkx*@|M@Z%%)tsSJoC9Q1g+*nzP$c5-1PT6F>01_O8!5(#g{%(OIHIcV(Gk~R^1 z)H&5}q4laKbT?F!E1tGvA-=z0F_n!&g|uhABW`dvP(bzIl68#b0G8vlW7&MxUcXj= zU96T|DgeDBEE7#&7Xy`O+WyhcUyN;LSemD+JczLmBXIs)u1GVhyLNEo#x3q1`3W^Gau zLGWtB@o%$QFjNf6=t!_wBhW>bR%VN5#d(^U(Qn7)MyM7#Es>Eyu?E z*#Wc`Bb`d-1l~=e;g|uI#4k#=_=AL9EAr=+v=3dqqUaSYYk^6yb3C1F`B1@L%|?7F z-p6#fdjJLiu=$YF`a|si%<-5&X_AGm`PLIq>os^%6m`dna2kV= z4mU)4wdO#oCKc46J9diAjd0QE_I8vD2|9D5FMnj+_vbe4QwdT1t8yh$ut&>WBh~FM zCm)BZ6JM1a%KAAB2BC`XA@idqk7D*Jcqa2Zz0TBndAFtC4sbP|Cr!4z?s}X>xXwj# zMr@1h+3b`sdTYsnbT5_qi)wi&67GgjpBSt?M#%bFWpwcvl171XusQi!6qKgL9F`Ht z*2JV7cP_aSWJIvun9UieaEjXvp%KUm@jM3F`SL-YQLynnfuC8)F+xQR?yDw7J0r*k zBbN!ciSaUUI_DL-9DB1_0KlL}V@8iZLfA!yAn2z*lr|)%hxh_K{UV2JXCK3h&_a)1 zLnQmk3daYYtlO$oeOOC`}!7X|mRNmvTXm_)l2Mrjlfldh}sq+0Sh8d?+J z3LSXryP8=Jmh9kx8d5Gi4#DkK_rP4|#fj~ihGwQvSJ-GUdur{$y-y0!yzD$lgH3R; z^BZu-Oz{0-$Axa#1}sAsi9EgJKoFdJLBbm&4`ODTycHwE#4mn;0@8#h7?KEQF?%TU zxtK4@I2%>WMbkL3+u)PldGWJu#y}gY#+|0V7fwafB4CfOK?vU0Dgt(x8J>%6y%&~? zk^Hzbhmz#tT_!S|E#yy11>Pi=vSs-G)poE8hFQ4FyYj-u!{-%T@o|O4;NtNoTYuH2 zKCa$2an>8&dJVknD0lWRT#2=K)5LxG5YuR%o9OmY9Gd41V)%TZ#MN>*sNsS+L=+t$D!PW;O5K&Yae8^U#%{)q?Gvc@nN=B+lkXvFNV_OWT&0*+W0>>Hhjm zPHPz}OP%zg#!`+Ax4hmT9DhIj*B1)z$#{>!kMs0jOFphP5-*3=8hZ3*0@9vL&fBcF zy!-VnWcbO4^`Z5)?O)%ixK<{c?M8>_Z&ti*>nFkCjc(oF%k;F?8F|~ye&^pSIm4}U z2ZuL@!hf$8;(moA6}OPN4L>l7N{jN-K|7A&KWpcE@o>|v@plE1qVert*`_1kzt~dr zT7JrkvyCWU1vH+gS!uYquD_Lcb^7AAwpwQUYteakYkauv-+9ry8;z%zmgDa3nX`Si z#XGa}^NFi2GUU30V|Nq``SH7!l%;VB6C&=pvd+-O+lip#`juXg^7|m}H(m6SG+0cH z2)7?+zN>eLK9}f zd!N$ka+ z0#L9uL=Xkr0%9FUpe=Hs5#+8bL>drX?)dPG^Fy8y=O~@?0f6*qkRdZLOuE7wCYDTa z^3qBYfw8p$oTEgDPl(_NM7WULuN1PS7jk~5D?F}c`{jMbY+N(~Ukvw--}Tg9|11YfY?t) z1T)#bm9tSOTDNvpeN9xcWpNj=S#Vq+B7lS<<|2a0sh4X{TOANiu;k+w1cIrkpF$Uv zXVC`G1{>6P(nk6dVm-`7tY!K9cmNN_i_Rp}gDh!ij6FEVxgdn^DU})_2}cBF*sNPw z)!SQ1$w?>hHG^JS=?IfLA%E6Q{;1_XN(FHE7nCivSG-k>d`oZ`Vm zDtdR5f78h$is&<^c;WDw+mjVw6a^J4EMP!5j6E6b!(f{l!HR})4Llbt%Jqyex-IHQ zuwxNjfe0O?H%p!sEFXK}$?<1Qq7*X2-X_YBrg8C2#5Y~2eK zDHG_S1)nSnp3zsmOm@5t3fP_wrgnB8bweycbqk&MtUY7$Dh|3D)vDWK<%H1nW;$ zHH1}}F6%WN1{FdomEEhF>Z%4LtGiBCd#G_XDv4VERn`5r8oR96p~D9HRN)Dg2`x&3 z>AZHR}3_tPJOI1lz=q+`ys`vf^``M#SRe@#x&+=;K8}74o9^7xJL3_hj>MIu# zAN8Zz%BcROQ;SS8Eh>C~x>egpM5n*x-72WBBIAg<<{Sb|@_Z(ir!$)N`ob2tygy18ZV>x3LmkZ z_;cW>t^Nk{s4XBb6c`DdomrI*&kuV$b0bXdOO5%9hG~`TB|Q<60XCY|1&r794;$|A zowR{TvS4t4Tgcvq(NXE_|Kz*5%4pVcG=28r&kwI`4L7@CB!%sA_2J%Crjk{$LpiMr z0gO$Z?YvVTUfrdk&iCM9Wc{miRZ|~|sE(jDU^D`r3SthLBc~n*MO95g_-dM0;9qAi4QnXF(=;KrdOQz>$|HnsK2{~ z!vWFsD8WxDWwD~uZm?LKr4W&!vD>wpKNcc#c6}D*l~Q+kdq=ki2G56{pXxUY%y^IV zxS8>V*-{-us3Ca@qGKkYX@!_GZ!3QC*WmarYixO}6X4?vpo_07>W_La%C2x|Gn1lu%T#5kRG=7_fn$h8}tl1Vofj z1VlfjsfehdNU;Hm2v&*;qG+gsBH6Fs{PtRNt~K}CXYH}q*=L_I_zM^#$#dWL?{{6* zRA{O{+tDIBGKQfvJ+jrf<-nxhd;-A|f5ysKtrTD(Zk#A11@W4`J^ST_X6kh+X4_*$ zEm-uX)O0i4FgX5Kwc}k`1cYGQ*mwEHAM}}`L5mhWFd@`C3G5J!CSBE z)<+YVq++9MiDZR<6r^vw<;ke*w><VUo05;Y@~^303+@hr$We6{RJcRx!X$ zKUrPwZcbs&<^y7Q>snTQjPF9nRGuECXiBq#$>amuEQ46f6`~4IUwxEfd1enUgp@1muE(Zbz*#W zS4te8+;pslt+&6l;xY-R8|5;PI2n2XrENnxNdh`3y3~NyRLGAFr41}`90E9QzWCsI z5-lja9FN_?4J#$DsQ8UcqP%Z6i(b*#bj9_#_IB&_&u+ck{AbqS{qYyf3k!n6o^5`p zS1)?#qk_9FoOTLsvLiQL$L;%LQ=rU$*i!ocb|RUdn<*SKRKB{z*esLWtYjYB{KLG zFkg||{M_-jneqYF{AKKHg@bo14jpaxhm_5fk(7tB9rcKKO<$s8NjwIb`lq%O65j^0z_hMx%ZMtE7aTmlscLvX@@anCpc{tma6hHc@AlRlDG;m z5$l@qn~xl8_@^zU{GYa8{TzEPxn4Ie+4PcKqVrcv>B&r1%*r^Kc&U_onaQiEk_aZVGf?sM-E&$`_sjZ$4SL`Y%)9PSHuDf2==Q!u2QYKYwiC z7Cwn-)s@{n@ss>-E72Njyc$hJ_5i~j1Kjss_y1+(TxFa8V`X^b$2xmLxr3mJ1s>&k zrpWToWNpo6HdXiK&tq9OjtB?`0W#^za2=UvkP0J|p8vUWPCxx&%TdBdp6F7|wJV@L zN?303`@z<&n4dcN>Vh`g)c3!6dj9ugLh#Ln#O@t}hMh|kv)|kk%HG-g_II*2 z?kK;GzmM(`I~~O@6Q+1xM3LKlKWx64ZFl`m?kjZYFV4<*y&IEbZh}UAoLGLI zH^6(~YHf^`AHfEo@0?><2xT8KRjV|>PQ?mQFNqdMI4zFB&Y)ZU@q&p_z2=_;7)U(2 z@mX(dSwv5IL6kX}iK`shE63CtD-Dd>G8j5>9(gDAmDP+1ypWyQ-vf7sNytBk7s;;|11lk(4h|?SOrvbnY4pXWG7vV6ElsAbf4)gf+Eo65wZnJ4XayYC#`)_ll$81Nx*4Z= zBFy?3hkT8zTkW=sZ-n0f5nAw`IJL7qJ6UrZ`D+@cV1K>)@%6(KC5oq7hz0EuH4frF z1N#q&g_$F$Djb1%jof>fnAtwN7km1*OzHKFoLYIUy2Ak7N1}@FXc5nq-3%9;5PhGF zRi3$Jxd!*|E_fqCTU=^C7bP9g_`#~HTWF8q;b-S~c%E5tOM8fI=gJsmePLB2ui99kVo9AvQmr{a|lH{ME4otp2hU zszrhdp2~fw7iSH3%#dstRV9ZRnN4PnBZh}A5+9;PdiD*>S&a{Ik3Up@((duvcv9ZQ zqI3^A?qkWy6OVU4Lv-l-x{dkTc~cvAxBui_TTP2zaS~q!9!x)Xi%iVYuM@M?DW6|r zs=icQJF&%#3=u`sFh&gVTzc#L+r#%(BK`>dzLbKws|nsAh)Qj`p51-MwdgIE!Zdbt z&pkmPch1-7b}x7>%i(P;G2Mk z3hy6)*s^`a<%E5{$X>4vsc?UqFsS7uacu)xRc9vS*m3Xh&Q?L}K&dqH)|=_Qt$#BK zu~ik)Bf5fwRI?5XRnX zoqQqnGt8$sH38G=s8LAjH9L6?&051B$Cb2merUHvEs9ub1B%I{ofsg49mN=n2ll5H0_6)1-pwg*?~kHZLrJd7Y@6XN;g zsOa=LSI|c778&3K!tVI7OdA>L2`XqFR6xy6@Y<7R4M-7aVKlyg)Nb8-= zoT_ZQhvPaRnOTRwG?5u0AqnS4Q#YchO2ecH>#wDB|B!a2WfEpBtCgikwjg(l7?1V^pv?NU?2NJP$ z(%t>q%by^P57V+0wB*F$s>x?*VKyS>)}e7%E^=v3wgfvkKh0obJUFeQZ%Is>J{9>Y zuotXE(6w4h(Xt}|$7ZC+bWrifYunXcj}msf{xHB{+NHcG$g^-m$e=bs@#*8VQ@jKs zY9`(a-GZiY)qurNoNzKJ<;2ZV!fSSl0olz2X^U{#P#Z@;iL$8dQo+lVu8ol*iEPCv z+*7|T31Vhh7z3DqJu=x*C*_J>3zUWZzcy7}8o?OvXdM)~+9P>mB*~zo9`7C%ns~$y zt+hE0Z=20Syoz^|`X`SK_eH#B?$y6vZM=p7EdLa=SX&COHqf)<$G+{l7c25_RvXS) zV!DfS$GkYQ@M~lLrKk1(eYGK0YI#C}f9CT-_wFo7$3tqPUP*g<|5|O7-%VW^`*ltN zaGhZ#;(MnAv`fC;=4Um(R~y|WR>Qvp8Qi=p@OkX+%Z>YnD7&C<1o2qLx_8vTchtDC z8^2c@!)vI!*GDe z^hW=#-JV#y({Cs7ct#WM@!WV{vZq;q^;!$+5NQKP-i!5GEbgy*t_%9eR8;@&quH@5 z3@uo+awg<`j#Jp-FzXMRS2kh)&Wl*t849^Z;|uZ^{Qb z-+&$V$hxDdO#a9rVq~=ISt^cCH|Q-n^|d?>in2qX@sKOc1AMOtRm$00ik_&*o4u)a z^yQlkM5}rnFEI~Y)wA23kQmzLI z)7>9$Eqa)Cg&1lla$ixDO367Z_rzsOMbnmje*`s$efKtBc?2;L21_Ft>veZJ2Bb_| ze6a;}c<0a8d7bC-uOf!#o>@iql*Iu|W1PJhqFBB5_hW$zyz+uQlKU;wN?J&ckHoed zQc1~<=0D0kD~{=?tD*WNx}sZ^#c3MlqCHcT>!LTmtatta8yXKr1%zF*oOpAHV0Gm1 zl`GU8D4wV^U7XiuKK%$+ar@a_7{H>qtXdGG6&C!~^4RJIN5lb!XCie?;+uFWn7b%o zHEl3SZ%;iTtunyqdfX@9zdL&8QR9h>*MkQ}_yMh8XEd5iB9r=rtrk0uoq1qusrP-H zEmr}Ne?GFAIO^w>xI+Qm(T@S<;;Mq{vV;gWxrhoWZnSLk=Th$+?``*qb%)dv@G6rG z3~G31@$&hV{dXL(=-Ba%6o@<;X3FOt+V#M7gJ$S-xR>=W2c7ELHhkHbu$pDeDZf2n znp`D6YUDjJS@dG-!4p4a_Z*DJwd|`pI%x4TfGfN_pjt6Y;GTQAP4kcX7U7c)MGBDe zdPst;T{@@a8mJ-ViazoHiEPp*zE0gpVCy9Z0*)&)g~d$ zTFIwfI<32vNek|+%CCn{l62m=wX5SKLud<_pc4dO2L=Bb@HA1 z?68)Ed*iYUP0Z8Gq@~i*&*wLR{mSe$v{oSmqtlxH{cR+QEaNQgB>pibf6e|;{E!e+ zgXD!lZm{L*Jo%Qj@bj*^6f5%#UXr!u4uLw<)i4KL)DZuh(q-*8}$+tykd1OO0F{RYfRgr>$NfL5bRp)}XKh z{OPLlzU?ZgoSjaI%0ON^&f1QnC>oWBM3_Kog_%2p*Ky?p>+~J#Bfx<}KbxO8a1BnI zvk&sf07*i;bk}0vYN=X}z4XZ7!JX;7DG0>ilB0m95dj~i4$MO`?a~fmj{9uq*<^Nu#*T{k7Z4 z&$OrjMV$rIPwx?hQTJ}c_vm*)eKzsx>{Na1 z+Tdnv;1~z&Q{9b4j>OA_&;S^r2MgMI^m*@^VM;k}s>Cs8QDmGGwT%VEp)`bO2;<$> z!gP4USD&LE$0;6rp>EeKad_S#bsR_z*+N2*JVYNE_;%~RlCdJj<96QmPcgX=nTH{x zI9P8jCn8kqYRqf}A~>p*j?LX$wu*1;Zz^3|ElmK@WRz=Dg)F8Fqs5F9SO-yexn3~2 z`r_BPc=VXAIRLxQpUxdT)W(-fz8@b@5grdko4!d6k6@L5az{9s)#FqyX^dDygj(Yt z3g3Q~Zr?h~uOtVbULWFR)@>6sE{cwz0f8#H%;4iI$;VqKPIm8hup|Ln4nUOxTLu!M z2>#>{E+Y>QcAZ2x##zr2C2?30%5N+jYq6QC<79-&L-N?kz}$I<6a%^V@v9uk%6f} z@)hcX+iL-m0=qrJzc7v=mE-%_2}xSv0?P3i<@hOjByL8yX!1y}!vVzrXs|L3!A+aX zJ>cfFlU0j5GJ=pEA>FJNk*8o`M&j_1eTF&vSloSgZisPNJG++t0r>a!PvGA_0ek=X z-uynTJ5=MuT;uoewp(iIghw~821;c31pe)mR;2YO@bC92&ALXYFZ)9cd2_wiU#GMn z4BQ+44g8CCX*qUn(#+STiS<`++<$LQ(e*!m2P#+Jzr6O&jAnT^>Q;ThH;H@9@A%bM z$7)A)qc5vH*1GxUDQ)iDqwF_Ujt~g>>y#$em?}yQegFHEw&=I)uYh8sdM>Ql*stcw zUhTW^CivzzOZI+omYDj3{O2&-$Nw#@r1{h#OVpC%uXppORv+}>X;+Rfd>*`$&gZ{a zH^3XKJPY^66=&a195O-Cy0Uh*MDY+PQ2X)St>}g4FS4{J=576%U#iPTO!=;nilNi? zaBqBzDfWEq^kjK2e5&$J0m`sRio)-J*EEYuNFvIlc<2dDHnJ%@p~F5$G0Eg(b-9yd zrxY`FrDM*+0AkiULYRTvUh^GqRCnv2O=|76`Z82rN|m3rRXv_DJ^7)4t}(DpK^~P# zw47c!)CmswlBo*6xVAD@p%{oO0Gyo9Ta3;;8_g#rYfp0g7g+(|`@meUfWVSI^%Vd5 zvnMCkU4Wa>WE=&dHic{KwK^HLJd&B1A2xM7c~y&Dmho1fEAO4f$7Umxt4lGWctE#J z^<7;afvX*tchpQ5pZ!=A;RMUEGz>m}!K>mJ39?qqQ3sTAqqj%y-9e`s*oZACRTo?o zB?QRb{npTz8?UaS0^y9PRJa<+#_Cn%f;{J4+UIZgyfgjwn%`M%NCukkKXkSURn;*h zx6||;D%mT~+^>}l;&`3%$TK?T!BauK=9qn3;^cfxJ|v1AY~;ug`CpJ88E+zoXC9jr z3=m>xTUGmayJFaGXc1T$j!Zp1D#)J*u*tl{V^!5STIh+D%tUF5=+ay9yG1Ua z;>DxAt|W+EZg0gZU{mSyr{CV#TWYqOBR}X=F8h2aGa@fYe%L8UzG1X8@^HKCP`9el z7)yAc>$rS8h1pq6>a;oTtkT*3Nmq-GeVG%gI`>g#-fgW(!Sg zx;7s6gbiPFXZw7Rx`TC@U_T^L&5PeKsEqfdwJV%yYFh_!Fviu0vy=OK&*19uWNIAV z9mfLOhSd2v`ZH5nF(!!xltUkfRtUL=BlTh~-8v0DL_zt(I-`g$kgvQcJB}9sS#Btem zcBL21-{2&fv^vkm_?%8r7q6)gBy=V;_4TFQBBM2KSe<523h%uccXQ1_Pdw zbk#MsG7^kGD(?x~@6IPXbhahO;gh`&j}`xcV;Z5x2;0dnWM>ji^AU+j-D!dkkxn!$ zL!>)(jD`=9oy^RRyO62^B)BXGgDrLVZB7u*o!YJrfplOp{16efGZ`)b>$O`;a%r8q zMRb&wpqdhbZ7Whn@)SH6Aegq?CdH*X+1HklW*&8a#tDa*7GT<4;^JjP`r=5%WR$X2 zs~hoY#$FssR(6Yv*Z?pRhQADcQ?8rm(Pk#M+Vyi5NmMFQyl(`h&TiMjMkdAmiSfB# zdtBXz?6x0Nca+fW9egQO>#5FytY;F=m>^lP%7ZEWUVGt7Do6!f-~aR zwh}JTQ}Un15zx+9s~`IPg+=mMlfqWFaR$qdhE#Y!Vo^{kS$f1HI43Q4@;oO6__Qlr z;d%kcg0$T~Y7LDQFZGm-vuU&@czD>$bq9=%y;deLsdlnYX_+y3f%qyCtHeVn!=myL((_e4Xg>KL#rAOgeh} zsM&8LvVJx0`6f7{dV6)DHv7((V2__KU#%`S_1^hN;Fa$ok{`M&~{zbq0Lqu0yDv2Su;8l(8p%K8Gc=kBdcTHX5r!+jQP$9|#) zSCxh8Sf){2vQ+mepi#?TwNm4QNyMRATr%m@OU>V+6~H)!3b0V&Ayi3ma>|gn2_y%A z7fBAa7bnkRdX0b&4AOuI_&|!6^HdmQ02yBo@QjLa5q!OcYMB2^Yi8Yk@U93>=Vz`%ze)Fl)Vxjc9TJ5J)6t@|K9S1PzQTP-kNK;=sEP z3FYKikU~5;mOrz48=1=YPQ zPf90iX|tM~SbVZ3f|lYvieo=^yrZPOn>At9RmnF80 zmzDYeQNd2WMp7(z(Nv(1$R`;rlxLv^vsk<=I~l{uWUVPKF_oKl-`f5CZe0geu(_J> zlVq5e!$#Gzg$45ULe+OK%cpZSLi->hY^a(Awlp|UBDlgeUg4Nq4W}Y2Pp=zFRGXJi zrDeo$0G128Z6Osh*uaL6Tw#)_riMVCzhAQLrSvstjmwsZxiVM-3Ml2MEz^Yo?HrOV zj3DKln>_P*$v>emnJuGQ;|Gqx7T>ePd=cTt)1l{H(^8I$6%3dbd@W43Vi6CWR=*sL z6<|OJ8ZlDk!gW8Ok0T;;3Qu(x5}fnc(UuCQaZlHS`Op$u2q^R+P;6oMPTFM8x#yq! zD+SW@hv01z*&GE>9NoDY`TknagF_5)iLfSnVMg9TIu97JNX)P{CxwYx+g6;SvTUM? zlfrOqq3mR#01jLaBB{alUJm4Bwh=+AXh^8gVUk>bAf$)RK@J5A69{PrNt{d)tG$RE zy|_{Um)I)d?i$pD%M4|XRb@`UsQfxn8D4~wkfkS6PQBKYLojdxH%@FUJ$>LG$XRaz z6~rO7{PX)hiFiXtl)ee*{0(oa+QlNB`BR6Y3_RvSGGx|n~b=*ap#k2tpJ zUj@!iZY$dCb@_t%?=YeI!^Q14@!gV{?$sv4k7JA--rY+0j3E@`w>Q0!MhfKN8&l~o2UEMjd`0aUs7vK4DOH1^Nl_j+BB9!>^FLIV$fe!7-=Xd^oI<01a z%H%>g6DIdBa+YKi7p&N8mF|&S@qUu@q42P z)kbkXoIz7^O@Mo5Trm&xXj~WE|VNIfs-sRlO-;3E)d8FEGVBOGa zy9b)smt%_pAv_llKC8;MdQy4$t1ZuNn+FU84Py#)@dCe579}^V72aWI?I;LEF+4Wr z;48i~e~gHuY|4R~R=^hM0U*BBT)%b)wG{=A3$-2=J~AzoQ{tIByppEJ4)t0sxYDWe zyWlY0BZJ=8@lu-^2uDfK!t=QH@k!9t9=nYX<8FPL5$m;T7Y9uA1|LU-BVn|y_OhlN z3K#T~ANN|=NUbqCx7b)tu%33ZukIUy=MvO*3QV!`9mq_A^MG)=QAdd1;9iWA>-{6IED%5g&Jhwzi}5>~sLSWqwnVmkK6G?E^qbhF%e9-_@9qC&DSbCr(-<1-$pvCm3Ic*UW~gZXyx6DlvRp;%nh_jR z3ZkKBWJm^yHe$25Gm16u%cB#V5MXaab_6#_G_nS)&P$oRjhj}g*oV}+A;L5;8D(l6 zcAXJ#GUGU_TM+XG74Y2njRL}A3!kMo{)otSTCP2XUQ!a^-ytQ5%jW0{taL%QCf1(p zuHE*-F+ts_OD!b05D_fGa} zy%Y*o-r~?sRGTz-Gah0C2*DkL+C1cN+6Su^&x{~(q}$NTF8wl3p^ZJF+gHf#=7BNOG%-MUU({ZMa?=#kfdE3EkgaqDImxiNwCGi_hC#zEjF=EpBuLF> zeU~WKyE53TM2l&TrFcXS=3ZDd;G#4b{5U}h)rVADWr5}N3RH6xI+|>GgFUpWieU2I zZAl_ced{PpWjwtal5V2+r^6=qP#n+=X~oBBsesNzNV1IUNkMTW)qk}`NxtkWI-XRv zgO=&OIro`XF$E;}>=8?2%dXuYXO1jodA?Y$T=dew{xYsjXKPP>&6XoIXw%}&!z!fo z9q%vEPo(+yMd$8KTDan_jo~$!hY7!ZsxSSo^Y#9x@uqXf?lY3&v|JyV+;B9#@Fg)DL**+rIcCvK#dUkN>q&cH*tA@6VUUB8g<78LU%nIZf^EjV7@;m3&u7 zbV4J)&Oz_1t#lhHo#6vCNX(Oix8Kgc4YvC++$#{mML+XB#(H%EXAQ6R!4f=va2X=F z_efRNlCA7po=6A)?Msg7HY;DVjbXdU7?2hV7otI(7msnOT3CIoAGKE}?V+Zc99;?T`{Srd_WrflQ8>L53#4{I#cjYIG?mmrOWLa3P_m3gn zlm8xi4_o9=cO2&yD8lZxT-1yJf+GmQFm^j1iK7vM;(jSL9*ky*w5~3SwS5sJby@is zWmgl)sNw|LeLW4PWQ(LQWi)A?N+=^fOwfqu^DN+}H=Ygh3IUO!4O?1&0pjt*=*fv=8j}H9OVJ;@SUTgZ zcMVuP1L)Bq9Wn$_klOIrLf6X{OFUVXq_h|tj6IGSqQWozmSfn%>+uUCs?R8(-YLB^ zGO@|z==P|XoxW*_k-BXm_IMIvYDTRKfQLiEEA+(h$yA%BlaVakH%;`6@u{OYR(90y z$G2XCW|A?gpP-I}nb)LKlwr@ZTvvY2@Ic3fh@3YfWaFN0w9LiY(MG!c# zyK{rf2x&f~`b1%Yq1fBLM{&jw6ac}`aHmUo2oB_aD^G(=a{rWvF3oceg*3>Jv}T^t z(JU6}pga?SvWEW-Le}|E1Olgz5a;F}7|xdij9=a1(|d962Sq3H!_^%FlSx2vB7C^= zz?(sWflT;Vve=0p-@lK*yamqigWT-b0CK(xL;bBle={vH*!3p0(f z^X_5ixeu;I;s>^=^)&p|?!njjGmrcc@6&Tyz4CXv=ZV_iP7)2t@JYhovO@c^ox-Lq zHG>VXgJ|c&+{;^QH+STp-&pX+?{?4Fk)MX2o>m@4+CJaZR6E+P!bcarxPI`#nRwMM zyFc4KxQT_&DL&fXJ)Av(zuP@;PEGffX2{7leu4wHf`-=B^7oEhZo84Mcl-NurMn9+ zDQDJ7lFl%XJrjOXtdsR|-`0$#nd%<@4{@dY-d#PPlm;~RoAb?%$Zs6hyJCOH|6U!Q zvFN)8MXReWHs9$vF!>kC)@cBQPr0=d$%c1v43lz|MrNI~IC$ zffCKk1CHmUeQxLrpWkDF&{O6r;`LzF&>T02Sk-(%pDPT-k{(;0akzYS%VtW~W{cHg z*f)U0)q7N>osITD3-J1F5TJwc$m;u*eY{qIJ3o5`=Omf78;2Rs+>AvF#M}^C)vah* zZ9s(z{Z$?*n5bmW@7cHpB4c1nDic6!l^9GU*5|T=m`{_ZH4ZV*zPaaRk{EoDI@E!% znu(1jTD>E~H7Y|Ud0~Le0X71=d|=^dxHzND%JPt5?-l#+7|EPNs3O=Pk^9D@r{+=ABl0*u=cHs<6ka`apmPXm7xuDUv!{a zI^~0@ggdoAQC=MY>vJ=OX&xmRwyWFZu5NtKd7oGQairjIL9`7NZU7%sI0=gA8%jLe z+Jwhb@U+F22iXP@CW=4j@0gmzl%2Ubck$`>?mM^TTp6QEQXWEVoYlnZhHT5n8c&F7 z=wea(+tXeLt@it`_3!F;K6s5MAk;TRa$(0qPdF$BwG~`x{o~^D!Tq^fRJk%z()Ekg z0^i%8FND3wdNnhCss(8ap}=#aBN<` zhOq6eyv8NM(V^1{xq)Z!PB^C7%DDUleHZ*MFgP;c<#D6fk+Rjfb*q{8n#ZR~NTt~t>E4%* zt8TEVq4n$~Nus!F=9yuRMVm>MehW3enOK|p2hXG6Wp6SGx2{m~Gr@3!T3I2`ohK z8PwNQ%348FgvNw@yW5U?dM1NDYd(1a8L7dp!z;l)(_#`%AEKwL%}1#thdcDMWcLhDQ1L_Ckn`Zf@N;q%GujP41g~e$|?m(AQl0C!XRntsGz^O z3i!rKTKnEQ3rLreI<)Mi#&!h#4$+E@P|+cb6d$_;DM-Y@tPhbM#|x56TAIzgHWRaE8*U-K3lylQ%9J(m5mfu^?HV&4fhA2q_mg_P%*Ni6{VBH-8yx z@*NhSv)hHtcql`vwL!>8qCVlYm~3t~W>ZruA)kgcbvj3W;_I-1(=T-XWZVn=wF{!| zT%`O67qfxSLfYgf2c^Ac3kDWiSF2bi0;hFgn;?*f=%H~H5W#O~eTH^D+EeU3;b?7w zShylELNR4;5P(PqnY{*Q(fL^tCr657QBf+ul@VX?>}ckxrJ&I@1*x!2_=pWzg>Yr4 zQ~RhQb6fEmFd0=tWgQLbiVhG-r$vK`8R9;ZAcdY02Qy4tW^0V!0h3i5`IlU@Cazs! zgq67dtuiUPTNV6xGM9CemZZfP#mBO{%)MGMVJ*o1*NmwFA^t+hXk9?Tp;?6_yr7`Q+2V#G8O$S2qPq|Lfr$8Qi6?iqMb=13gK>C9bj6Wkj%!ti$EY42$~Z~jFu$UN0O<9wlyVf ztA(e4O zB=ETi$NMZ7ljIaSj_st?jU@6JC_qC9vB5I1x4fuZ&qIuZn4QHz?|VVfP&{! zh{^BCR09Z%Bhn5LXXqA?bw(#EL-u0|_>}g@No&Wo?x=6BbmtKmWy@mb!ZXc6Em4yO zA^`;Hdy4KsM3T^MY>XuUC4CkR^=4I3CdkQQ7 z%AaZte`oNNO{kI73Ure4ym z?k?;pOdty+uYFHED<*7C1_qRaNE;Cv7Y*NC#OU~_L}G0lv8<_ZoE7jvi~V@XM!%8x zfdUK|8<1_{?i|efHo*mU?q~0!ww?eV=QHf3{FFSCq^+QVe^%+2CpwItzQ`u-sIx$D z^Q)Kg6{B+>NrR~oYqaxegAojs43B#yzx<#B6u4k+yCcW^XW@CdkA>N$B@35``{s#5 zO#N6I1mD**=#VZ06rn)&2yub#fGl;997wpNK>|On6vJKVgq=4z=1)0#8nC;_XGEf>A1qlb{{U6yK&w-I_ur7 zGBg8eKm+f%#5ppN&#j1ovtvBl6g#7;*$a%&Tr0f5d}{G|o73hS;PW5l{CWsOt1zyy z@SHMoAI??_3&7(~BNzmOkWGAwFzFH*AOPZ6O*OnAMgefZYg6h2LY~dVh)YG#vH&Ea zi7HL|BnoFx2vb~@(&HMbO)SfrjC6Xk4i%DgxeVvoB!4JCo|i}Tm2^0e1{G?WO72KY z)?lX4WX^0!!=-aBi^E403Zi!#so(4maRv+nMBHos<6bkg%gI?`OR>3c;(N2ik5dWg zxI{(CE%+%B{YkB}4+ze^Y^VG{M0)8T%x1uj9CGWjmQ*$mVZ(_i1ny{@6W)!R-;SKOH-C{>bj zBD^$G8t?QFu1j{-oZaxIVclh|0GkgF3p94$qwBZr)|b>vy(wSvxaHPd{`J?b*Fp8ce$*ZZE#SqW-ahn_VkfnyxnU(1^}x z?OfB*SeKsZKT=(uw0TAAV`1%ysO?Am z{r9Z3ugtAhqF!w~>>n-);?lX_>E_-(QOO9kSEO zpg;nAjCs6(P9dnpsVr@RxQO)H+E$F}{x%c_U1xuX*%>$E`UOt$VG%2H*;Z-=UpzLx zEpE^5)+=}o-;Yvutbd50i*n67zVxGNTu`LS>a9(;^l2;ANTT_4BP>N}$zU+SzLlW) ze#fo^nC=&HwAXy*utG1)u<-5+l}dlGtG-Hj%`FaLTN7acupYxn5I(TCF2M9}Wt6ySTF9F#v@s3l<1FxoK-zY|qlC zYJZ=QjeHY`DXk5-kkz92553P>I4<>#N>_VtLtkg^4_?RC3O@^e3p~tXYB`POUuriH zH*V5Bl>&jpfXtzvEg2r>$x`c9mjo1)xB>#N^{H^K`0;ux0iTghNi7_O3AZQauGs9! z{bn^TKa!I2)iXOr4*?$C=Bf$Bu`nv}B=(S$@BkHUvZEBpk?D;$G`Qe3!j>;M+Bu+1 zBA_@5{b7z)yAVuSp;7?g^J$>8Euwo`AdCTty{5&Hc;(EZvyNE4y_4N>fviLXMHxR+ zcO6tyfd?a-Sm|W1vn5sVa5n-}aI@8oB1G+l##@|Bu!NOzh4`Out(r#>Kn!jW4i)0dE4d}L9sigRqfmus*7fA7XjyM=Ua)&&8L+{ z($#cQK9yfQGn1I`tZU}0$Xa}SfN$UXc-afIn34hh9uus&jGuDk**08fERaj)&b#Kryl0>k#DHt8p|$;OXH2{B9U zKd{C9FBTa7Q|A=7>9Fm85&EXT+|Ssn|C+${fapc>oKF8Psn6FIHYF8+x!q0y;Mz8Sd%L9FhYpHQbz}!}@0LN7f z7a?pdjC|>%g;QrDGK^6inbDC%3139kzQcjR1AKS6yhwzQTVsIC$WWquO=%{`LwtBP zc(VyfO7)#o0rzlNU3!4FF$f@DZ$inI@hUSm#vqj@sWA5+Pk$dTak~#~cq1YW zU?(>&xFvu>K{TSfL!pd4JP&ClQsq;AphKBSS|Xt0$ackR&`!Jw5uDFiqELxCGo z9z|92mg=`2;btB#PT2UBbF=s9i7zF}qXO_{7W8qG68Kjn5hQyZJ7v5vUHRL?CmwGF zhcR(WJIOT+2Tk!Vlm_m-`op`0{FXivi#lmdyhLP<<#AcOj0EX?%Ef2rGW9I-tiT0! zvLIcZ!F$d)*T%7fUKp98a&=I9*j2rBV>A}dRh=9W!;nz(3o?0R0E=(Usct3=3bv$s@ z^TbP?FN_bIV+dd9+t5uSh#XVzIYgfGl3^@Hi%Q8;)kW%r3pN?6wB zXLM`f(nlaE#_v&7yde`oLA-U+7oOSCdl8CfICN=c-qymgDF`eTQel$F%O;TwC;AMX zk(MPK1eOAy@eE?sNsA1^8?xad+d${i=}qm>YDmUahny5nmXx+(D9Z9DUlalNN`^<2 zOHgnYOjw>I>=on}Z|lj2qvSIC)`#LGWemU6nz^b1Ne*r*khmtvt$2Z04gjeycZx|Y zX|y_3p7*gkPkcG=WUlu*3Wy;i02|9yGkZEq+(`LdHyY*<3uiW>J@Z$a{A-QaiI?)f z(Bu}`K!JpX$hc(&Ax_<5ibh-}S^fU00|M!2;yH9-@N$@&b1vYusouv$it=BFpX^`RbfCRVDh=hNH6JXck(n)x83NR5zNA*ESlHn$C zaKm&T!RNfN9S$R7n4U!JK2)%u4MC&}25<;(R2vYrZ6Nm%UwXg@Ro1MywNZT12G^|AF1kyO`Eyq1d6}{2`ttU zZ;W&PurGO9eQt{FYTvMaYQ1CTjA-x@3ds~$-asr+ClOrE4}PK!`Q>_ka=9KsaMp3F zQ*nbw>EXUj7Y_TVrx{N8mJEmHCNvlZSFD|ThM1lQWHPo=2Kbp?e0sL>=5UyZ3;V#f zii6EE)10-jeGuRwbom?_uC@eOi$VZ9zTtVBq6~M_>i9Xm>z+kgwOBj{v2ISnq}CkC zz|2xFai3M~U9P&Ef3E0w-uW<~#X~_9{4WkcCkR=obBWqfl`p$*Yud#F%@-kq%T=bJ ztB*L#ARxGx;qArU8W~%0F!L#UPM|1M=5o9$b(KSyIRpWU(8)#vBN{L!gWx{<8x2IY zmo-49T6e35}91_vzM@!jIj|8>{L5U zDZ$0tBrsu{No}5{S;glj7;HsR+6O7^Bf*h8Oao>0biIx)1PgscwXd|lq^6UR(o_WA z+!`?=4NTGz2(~BMvtEbPXd~CC%YhO(mHTuu9}Z>6&t%-txR%VoNh5OGOnk4_{4qHx zvRT&`BS`{(uOI*WfpSIpKOQJ`&=LPIP^w6<;eqns!2Z+(AO)Ak>i+V7h5d=$6>n1i z-B4->eC@UQ@}K#9odVPVg+pw3PU{kSpQ;T@jBMIHSkP|o72i_1UuDP38z+|Qr>9L2tWRHyFMhwqxZ;cE z^SsdA*A8sG3oLOLP2Z^?nwyP3{djxlWL@yq(kCTp3tIcDMG2}@J5PIw?W8(ELsvDp z{eI^@Cn-*Z2j(UHKMm0>LPs~u1HB(ujB16 z?-ieel`#~3?D1t62d3(Gnq511eqA9(RjTQ9OJCmpE`B68d0X4`wf*#>YdRpA?rH4?$t-;zj}_3mbnAN zQ$w}_reuroK8gLI;g94y@a#U>z_FClFWWon=Mn72++})PIY{Hafk4}_dnNr1puu9eG;&- z9D%bQd1NKb!&=zyFjo;QAJTY5nLM!2x_?t!8i{*9ey_*8aPCG~p(d10MogyU0-v~>E zCbfY5IWolh-CX;oFJ5bz?Pxw*4SJn_J!l%*aSA}25CC_st=M@W6Pw0V1do_jTb+8V zTYC-Xc#cMB9?h~2fGePD@cdLXbcg(aP#A@4Jw0S}*6Vr(IXCNse{DYSG#LhA60B!M z3IGZe5D7|_Sl#JxcIP1hXHpLg&dUZ^s;O>*fSNG=w&pvJEql8rti$RH+MlH=T`8vl zDnN#wN%AgojI&rJDN_{S0y)e5mb@YRsCAeqn$@phoK<9Tno@ARyA&A_ZDnl#7}IU0 zCceZ3gvivQ`nRp!-knw}?K&)ZpxEZe&(H9*I$Mdy^%6O7K z`u5aOgM-j9fS-XL3kAaI|2U^>^=^b)_JGxx%!>?{w8}RRCEFiI-(ST5`2O-f{b_)M zN+T$4uwK|4iv^OFd#g3iqV0bKVb9p5PVVl!UZj%X`6j_ z9J7x7P<&_64VxtZHoVXB^IVjASmmn=9|P-ttT&K5Lhv>1y#yK85I86^?bq!Try0}0 z4A(X(ZSk7rGi|%ul`nZVk+AF&{uUE9&m;gQkSsT5x^=}Hpwg74M^1bm(f4tE7kE9g z`G?i%@5ybxOG-Dv-^w)a_MhE$x6U}dKl*kltLUP^&HZgh6bS4b@6M&R8yEVBG2J=7 zeD*%cTb8n+(QDWMFjn=GrW+zxX|qf5@G-NyGF(9FR;7OQaXlCSI-bMhMkSFSseZ58 zpB$J~td+i$XJb$ql{;VgHu&q7Q~EV?dw*chMb_rsShEU;w+;TeIs5gR<-6`rn@eR1 z>jK``x`Hd7u(fbJVKx= zVSkd6`q|!3CnWFw@0cI=Rmtr9ck|=_n+4^wpJDN9@1>Nz2ibazOIkDUUt&nD!xs>z z*FvrL12E}Mpj_n4U3*t9R_Y~yGNg<E<;aZQPB(VPuCM3vONDXHk3OCfa;CQs$2 zUIj=l(F;hg z()Ho`aiN1RJB#%ebuV`d7|x50r#FOcwNMZ)`}E@0C&g%D0z~k8q49{oBZP56@}+hE zm+vnL70K;B|6OAO+bwtfqF;;UJKDRRH{%@M1}7VPH7Ra7ye;my_wlb?nZ4f?o+C1h zFMKX9>v$nqFcWwbBG^+F-5Z;-H9@e{oQecRD+^6a_~o&F)K4k4e!iPtop7(H%+Ix|~9kPTg*js;!KL9+KB9 z*HPCzYcP^(wVXDd-PY3Nl z|B>{7<#dX42I%J<@yR$AlMz&&5h8solamp){MWOS)i=o5oB1>S1hqU9)ODu~FbpC_ zI{YA?>epVHNd?s%6)r=C2vkG!`6GB8{9i#?sEL?l<6cXg$XL!u0We9mc%MZGSioXV zLF6gf^)cDkG@$}i;42STfj*Hz{3|Fk280wobh^_F`p=?P6GfcGW(V{;t=kGD&^oA$}k)wK*>!n&&{OeXtQ(Q9&x_K^Hv7H zQ4|~PC7e1yZ-@XB>3QSmoHmF2lR^1U(KtCH6AT3a-847>Un#z;B~S?TZ*I_hfZI3; zgIy~zxdTr5n`oCmq}_Xd!{7BnH}GZk5gPcs%OXuNu>@cX31$6HSxSY4 zQ~B;t=2h69fzF66r)QzlxFw#qOK*aJ1R9+7+W*OKZ&L=+g9&dEw@4nfDrOXHX)lrf zUScf14;)(r7_d`Rgymmnv2q`$GJu5eVQlLcN7A>LrC{>6I-ej0=LC;BGJA0!*bp!R zx`lx19o7zEAwY1yKhpsQKt9+VMjMvj(>md*RV+G)Tjp3z)10UH5prJM3ccb`7z_Cc zUo?_ZGSW~|Q<2+kx^t6=GfjgbStt(<{FRM@rZ=#Siu>*Bc-OhSt+X6{r+jj`Bj{y8C--jBnV4CL7J6G;8@JKoW!xB)Z$bTcC+SdS4o(-CpU32Tu z+rcWH>4^uvISX3nPsqTwy+$I4kgcGbNQ3|!B#xbX_w%8nw+n(WH9v3fR1E>LX%|O0 z!YdryB_iOEUH35yx3GBe*kH)+JIuFUN=f3?-xr`_CHo4vHjdbw0PR{t<%OFW%&Z3H zQ_XWiF2#I&bvzMB#sh1=arppQln3GC&ET?t{HxXMYSR;e+4vJA z0-a$@!3c6j|H@9Z)0t0w0fPB$t&2Bkajw|7N?B9)=4c#Ai2_*Z7ls=Q_{_PPoM zisxoO^Sc@qQl182JQ<*?4?&Dy*T#!1Ow*S_Zh-1ehmytT)iYf3<3}@8RIQ*;gY>IuL%bhp3Jdv{qV^PA3 z)pxtp`uv5uOEeA|n4WeGUd?cmB?eFNs>PVc-u}Z`{ehp9QZkKGTe0oeEj2#z$^V0G z2N?ULCmB7viP%*jYjwY*`Eh1J)wYwjk9bsc{)M{BR1S~z=7K?iK{>7KI{pYq>&fk~0FPZOVmHPDbBhWaEs210W`+n$XcG~W| zVIJoDZgzF8EU28Q?0WfLz%ALIS%>(AbbUW1G4$ip3u_h0R_~deAH5#UJuHs<_4_I} zW&P~eJ~>?6T%VNs&>L~7b4LeI(zzm!xS53Qjv{VvtCKUNf+#lQ@lMGeql9hu9RlbE zZ_0fn_9s9dr5*HYt0C!C?mZV?ISP``=oQ1m2~;@kv!wc5o1~;G+Fq{6=h&!(n;F>9 zlU8is`-VX5@u({ex?(Es85T71!7sRTNLHR!*x)bWeXU{gqFRfujJ(g&%uK(K-QOqt z4vsyXtjSIMvJcp6xYO};@Vf7DuRS{vM{CbV-SLpvGp;{yGz8*T;kz6Q_OS35N+fd) z&+?`Ao`@utYBYXBBlr(`DhuC8ctH-nk_F_`dx}?d8MWeXVZlBQtGH z`O9^?2aMW$ZjNNUZ)#uGR}YKbdA@P>&P@A{*}J?)I={LW-<39W5|3E6U_$Z%?7zvdIT zy&ZUmJpDM=(+2U>pjhqJQ^QF?PyCyYGYd}<8wt0b+wT~52b$p`i02UWGXonp*n!1i zv91}S+te&U0_{QMRt1~**q5EIGr#{%7UKIZJ?kTVs zGguHbsK0tWZu$jzVLSCuxGA!rqj?gQ_G)TPC@r;;|- z*n2itx;|anAT2)mMDilw;|ES9ZtfyX&38Nic*2nwL7G)ebOFq7Chn~OfHWTH{?Vrj zd@~O~>6_pad9$fE@W}{?Qp zkMiZ&WtFdg&=6)7IJ_xTnkLZAM!NH3Sb<8@EF0M$z~d-3OYt|SU**nRK?GyIw8J7( zV@Fg$?D}Uk!0Z-6QUw!dnv?is6x0cC5w&cmboYp|!KfqS$M;jxfK#$O7Eeo9{9L|9 z>9>vnKO9&<%rq_2dbRs*P=H|MZ*IQ~K+Qzq0kIW23h`@*pP%&f5MY1@1Rk{%e44v{ zVK!~#<8*j|m>O3YHehEt+>J}16E7+|0g9ernzjid$EP{kZfoZxb+G~bIjHp)Wn3bh z3HBKrAht}TA-x&~_<#aD{GNLLV%Bm{zvUu;&BaiHpi*4WyJe+T zORRstzv+kDpZAT*JO!5|4ox z2}SX`DHS+5SvIEn3VmmjTsx4VMz8@35<7vB@OyWWfN1<{Z_P<|a#E{mJTs@?nm9g; zt*iDI54RQj$bbTZOdP)xWi_SY=ERq$R90M&`epRqmpu!M{KM*>x5XzL3_QggHV>0n zV$y_4dduayeprX*ydQg>({Zu+)9=-l6nJMcc7MH=)WgOM6M%qQH|e)r@_6v>;~S+z ztzlgQ{k}>m*RL+qCo$4YB+<1RVTh&*on~av90Ha85S8O^c{?}}xQe`UH@c?Y`=S)Z zFY--n;M02`5b(A`*h-RDBtyFGWaD+xmwY#yb}8Uu=6c} zM~Y+>YuE4$)22hx_Un!YZ-|*Y(k6;r9zKNVt{(L^7Kof^>V@Zv3>-7RD?LPCBA&O* z4RTB!^^AIlu;kO`=B_-x z$>*fNR|&1jN$SN(Yh?+?RPl?Bv{h7+PXuj9Ir)hOjVxyP{B4q8Cv7r10liFHF;0X| zCGtBGl;|{+W{PTO;?s^4fq?{#m=un&fsWHzymZR&WXij%$sU1aWB68d92uWUrPDRh#RUJ+TgT)1r6Qf;Su;#r zIVqkVla<7xzkq|6XnP0+n<*V%M$f7oakrK_jjo2mTk$%azs8{s3!(!eIVkkn7ClYnetq0vcyZGDSCzGcrjAfX(A`#bVKf$upsY7gKmOu_Q;rKY!w z+eV6!AXDNtW0~Nm#ss1PKm(6u5G(6su_glry)~%?;$Rh8wf@w2}=$bo?Q7Y6cUf*F-xk?oGT`wRh+X&%PX$J4}4_<2r43& zqxf-9E`VTkjUNjGBeb7y1}$Hw)7`Wz1dDIm00m*%RG z2223-a1mSfvl@z{wX);BpPP@ppcq+bc?=TIfs;uh5vn_UxkwQ*kik9vqYd{~tm=p9 z1v>7VM{L#Y+f@fanLKDS$HB?4Yj!hy z3?&dCcSJNe*hsd3qjjM)Hb?y$qqy9%E5edbu8W}|2@HTz3E(*3ek`DZ-@hyP5Oloo zCMJG1I4?fkDXDJFKn-5%B z;nlCO;0P)z0qc_FQijehYo09LdxzokIN*tD`AI@8=p*r?-zN4`Ohi?3d>8Eh)^iVnVcHRdQe9sP-vs+wvl%T#__TNlu*8FM$zC)p)K=#I~5?equi41RnkXz*6 zx2O`JYBb=5NmV1Nv9qD7a0PcYMg(4$y>;#8HR&8(e5BfHai!6~UU~ier!epalk?i- zdY(x{L_5B~#CL{*yVH85);6ShUP{U(vtz!34J1 zX3ZZP$W!qC$V3-T?AGvU!kWrVNwEIzgS`rM7I`YQl~OuZ9*)|XDI0(It7lpUCWu)1 zcONWX#mhYEWnGqCpdJ=u;5M55dkgLIf%A{;vpnzKUYIP?sf`uWB+Hwh%;@sjuG%Mh zph@~C-+Avd*%tFBI(7$N+`sp-)biH|rp~e8f^yJsy)#UsNb~4xl9-@UFl9)>VRlPB zH)YF7NV=HMk>o0cI5-<2>0>|iP~o9hv8!s3CS>PM3H_jnEKQd>Ir-p$7Du`8y0Sh> zfS~6S1)VDphk&@tUMXT z_z~9>+AC!Ij#`^7?-gVk2pnYF}Uc+5YnvbGXgtUo#QYOS2&}1S8@CFHJ@XK z{1%kr>74WV?}6PCB7CiF8_DV1pZ#ITTc z_-T0u7zn+|%`o3{^dND+kj81MPag3>Xzi2j!!t$awha%fIA-k62BoAz_oTgQDzW?F zwqfZ#16zlW9CkK*ZE!kWDvvY1Q^H~H#9W{J$!dGCCyxg)GC$Q(zw$iRxep~*4mZs| z##Bi3DRcxa2zvF9BeJA&onX(kq9vZpr}*RN7IyDtdSLWRftJ4Q<71&n?KW{yM5Emf zpYYdJ9)%C3d`w)ZTMpEx{Z7#;5ZV(!uE%IgH@17#jACZt9j`-q{5cR=^EFUCvuHvmp_A2a^*{jci76;ANr1l-_A$Ru1qpBx2{f+Qo#OV z9VjK^NmJW7+{S+4H(McfhvvTd$LY7tAm;S(Z#y4^q}A;u48#LAf_3&Ht8P*23mnI7 z8;ir{`s+qvQwKYQ&(?nuFiD)+FaxH^9!v&DfwVy?F$ZP zvoe{)=dZFe*SDhB&^I`xIW$`>1`i}~dufma3h+~({n&;@Tch<`OD^O12RMlmC1WW5 zBwH|yfl?UDgjr9K;-^&83gnc5x$bD%(tM{{sJN~oea@*@%yupb zLSxFlt;b0Pu#ybFFfC`Q`}9EIcEEYniB(jAl_Voe{$ZxVC21!c*?c9&x+Ab@Gw9+s zU&LR2C_)@`c5(A8%8OJR%NWQ95};5qr!CqVEEg|Z%DD!6HsIyFYu_8sbJ|W!O%d)1ySh8^9*k{E>P^H!A1ArRz(n9AI z8)0@qp0;q&&t*pfc=p7jDaF5Ob+CwOdK#7@Qqq-4ns>y*2Zpa?m8%v z(PBg&7c>7EjvPrvz?sm1byyKO{k+$&@D%viA>b_Q3rVwrhOdVRf~YE>hgT4_xUD%i zffFxQB2#KJRt*661pYf6TiPHopbAm4?i3P48~3dT2m9V1!-pf01cW(F?|v|Sj^<4ec28G>SPU<@7^v>1VC|jo-{|BUmaYewa-!4*I|H4*ZVN+Qsc%mXgw1up;14M6x`^ySg!6vs1g)6W2Uq8 zBwwuhMblHj|fAPsB)*H)pV$}Qg7MowZ}^3jko(PJxzdZ0NZwri#sz=t5hr84VX}I@#kAd z{noEKzTaKEv&X({;cqh? zJn0OM`Apy;#I*kIbFU6L*?>Iru}1r(GG4GgiP59# z&qZEpK`^@!k5ZHLk`eVOi1=b;7}c1kCa7yee~RNLN1B za>x`S8w{!vJZdpoF}*qZ+8~qc6zVS?Z*+zZ}W*5Me-(>M?W(2MHB{p(wzdMxc6qno&@8(3B>GoP}ty zoAx$#LCgA^WF^+8_>eMZQJFfOi0+`A{U(`iPWr~niSkpq2O_dvmhqP2y{_mu)S7QF8oZ01koDTyT%RpB!u(uh4qYU8{ z241F6)U;6Cw@@-xgB4yVd%IA6v`}%SkRVf}Vp^o;TcjRaq*+m~rKaR9!GVd*9cZEmH|$kPv;iOt6W_r|dn! z#!XXkhDR^*@yHx!=V`X%8rOeu0rzIG>P6WF5k%z`s>dqr;sz0dW1-><1^7I&@G!3L zHYBbMS|W~1kF;LAU3F2WjHy+LyKFNA03Vcr;)cEc2zMO>phbkiSdg`fQ!6lM|9zLl zLP+m}u^+Nksl8Z&97tvRQt9_a3uRT=p`xMCTr~TZa zWcR4c`u;pP3?$l9FMe3WNwX`cWp!I0*Y*06*9ZboJhX&Ah4>q;<-qn48mxFSX4Ob# z02qf~S;(rRI`2H(exXOkMpg|C5CI7W>?WGgREhAXLF3M$%t}30RIj{UX+Wr5TOZx6 zU??~yA?4n4DAooM%!L6gNO7#^hH9BeTw?*|TD2_DJ$Py4^2JvGpa-BNAe2}q6v(0& z;?%v;@^}_<>AClnqJ8+_J6CYOuNr1HpQ6!M^>289Ay_Wtn<-Aq?+Q)3UT@m5`r4&o zm+*C_O&_h9Nl7?l; z+`S?vXLHM;){fUaM7an$wm34x_C4-Aw)&#%*{MojSj%7H|SBnG0+D?{i*O&$Llvxt@m2(hcDF=D{HOPy8Txt0(vcQ07GRL-MRj072} zx;L5wk>Qk{scJ>+SQPQgI``%7xdWK{KwSw6azJ>f#LYSCjQ81g(+7(JqF@4Jx$42{ z-J}TuzMO|D5c|(MI`!XMvM%yYNB@&0J5zs*QmUu=Uv{<+?USb?1oJ>4ObUKk_qbG7 z|6i8uP_6ncQgV?4vwR!bfuxz-FQBwDlmS|@ZH?YHG+|>H-r>xuZ4i|@MnvY`?VcW; zUKJ~C|LklVjfo<%&jUu0t~L=Wwt#74+V|`_H7xnw-<@p>0|BX4uX_1H5w;t;EjL4< z_TeKZnt@L}sru<(G$t4;^($(moLF~*uYDjH;o#PYf&$SMGeRr{VR!AQX|hQixC6F13myhqJbX zo&P?0spw=kLfl~)Pf~kSCnjLy0e8+d@1Z4s#z|a2PhBn#J2%SsFsJHnnBeaL&-XZQ zn|E$pw{oY1>#^zSMjHkGTe{W7qR$w;S$Hj7<$_7z^Rwe*t!D~*;g}yS1MOcXtk>#A z0oC{Gfx8W7HSOHm_U%@E!Fr_r<7bCbvJFBb8(pVol1qM)t>Go?g;6>jKv(Wud?PT_ zmB;IK*9s-?mp7jE4`hl$j~@HgjW##au}ict@E=0-tT!im9}@C6}}6p z-bW_Ld>JL``*0q_|w_$5PJ14KN&365nUHipGftKt; zsZ;B70~$Bh=bsw?`mc4g?DPWO0{-(BZt2ty)y-wGaoGL$pa1IUHL5iR2Z?#Gxju0T zw_{_upa9&3;4fI+S{pgI`B209=jgUWu!l-kBjeVJ>vlAZ*C&XzWcOU`jkA!LgX>#; zx>tAeC<DI1A*I%#Y1%IjSy8yT#9l7<0O zi2p;vc219#44E2V_bb2uOK2`*la*;UVgp*TbJ>$YT&rRIKAix4VDFft(4}(Sxt%Qs zyj*H!`G*)DUdQu-1=+G+2Oez{76$x8vxz;d46D_-f)i-A(j*fq49qh!*X_(7#WxuLsH>T4uxN$y-cTJ(WW0RL{*6b{}}TO96f;({d&pC+d(20l+?~ z`W)^IuUB!k{F`+sF(>RzVC57@$-IEM70>HcQj#Xg2Z2S*^+3fxyiBWibNqrZJQwI+ zMwxf@KbM;>BCLI$)PNJyWYKKcAEtzLSHHU_Kmict4(r_N7b(v}lR#HjK#+=p(b=-R zAe04Hq#&j>Rmq%j93qU*jj(tLVP_M|aoc^SC46);!NvAcQ^gXnQ*%052}zP5|U)3|N9TS1B8C+^@ORv_4G$ z&?UkQ%ipy6o1Bz<$$*Jd3}pHA%=?So`Oo-=vzZjN0hRu@TS9pxz@aaNI+U8OOYX+R z01#jwIX5Y?G(lh`gLL2K!}PmSy9h3gw0QYOJdvlA4(WA2PxaR(La=*BQX%^&mt(!0 z55kh|0nudqYCxI8$HtRU7pm@Goi~7lv7QE_*5MFJP1TC4671^I9!!7iVEvLfP74ogTldJ1bG5yAHqX)O z;Q^8B_pbXVq5nD?iAX=e)%C6 zu2c?K~b`fbCXBj(jOK0r;0z?9d`OscfoN@W2Lq7+0%F9h18@;fbjTFS$&=u z9^BaYb9OLke(locw+{9W0zK~2fD(iaSCQ=IWf)tC2p4od)VNQ#w;16X9{xsR;o_P_%;M(%XO`^7Y|M*)EZO^O;JOvAi;Hq!?vdN%(cQZyq(Bg+`Q{v> zpzDi<`^w|}oB!=Nz{bm=R7IRf^ZaGwu*(MS2%Cm(N>-{xqu?TfK#a14P*RcgtP0}@DX3|Ea614&tNU))Kkd1Js!kj<} zK!Zk8Fg0wnD}XFwVS;Ir>6waTJOZqFMln%AJmkkeaCZjOkd3}dO^jz_?(hWixGEne z>}eh1!CXWX6%|E6h11}cG~~o@B#2olWeMCN30&l8&@&bD=8*I9 zOEr$CkT6Uqj95?tGDWdzKC^_0ZsI^-6swPs$q;UaJq4c5z@8_dWCjqY3)LG~n0OK# z)oq#L9S5PIF0<(!1k6q@eAhVqOeb9zt>Qlg&G1H$dB{Abz+FmuHUoQ^g`zT$MR+=R zG<-jR+Il+Kmm?KK&Am%R2b0qG`3R(T3N+AAK~#*+018z8O5c(a|D<^Xs5}zN89=qN z1S(mmR)sjG{@n-&gcAAVjRUvYrIR3#g_in(YH%OM@z$2N~tnsrz?y; zEywQW=#@KaMBFY*7%fX&DWl1hrX)h=9_*qoS(w zc2y3c>X zVu-?%05OVtTbn0@i~B?th91TJEI{*M8jV!loA4?F(*`c|w^8 zC^K-s@w+$eprH?iCDQ_zxVWFx>XnM9^_A)w);=&^1(0D$;mBhM8^K8Ux8N-^9NY%^ zkbVfxpt5@UcJ=4ayEe20pufF9gb#)c*|G&h^&Eyj^w`8hMhuR(ybhUPz`15u8{N66 zs4YN=#LY^8NO%~Sv+4rzLgKh)`@nu85NQUe5Cn|Q;MT!UFW&Cmcdjg}Uf$#f)2Y`S z>)YiT4Zzi>BOoSLkN~JLg#OfR+f`ZrYVgV)zss}fLJ@H=fQ%{!FinrIflXNzl4o9# zzn|p(i`uo!xTvwVMhN?W?HS?C6<_yrI6erfWuZiY(8#tEPyhVJ3w8J8owa10=%3cxX-fsAYBmyg)xT)BO%S{L5FsokFL5O_2mmOz2PKw1$KGE)+RbPSGmnRyc=7^poE{iS}6~y^07E|(zx3HX`g5~ z$O^zqWfK4Exb?^XdEDCJsVMC~Q+Azi*7RvYtKm%B%XR<6t^a!DuA1bUdO_Y72b_V& zwff|qm*DKhziPGhY=e_uDBV4F4nn4<{OTB~#SQ_Xq$#pflA)jp4o#a4zup50 zQrWGnhy_VZ2LyYvm4fjl>3g<(tN)x2D-;9dATwTgLx|U&JR|B<`^#7hqwinh{z%sq zNkPuatJ38haAQjoFUE zW9AmeLFZ@d@V*m2+eVHx{%jwM0<}FiL#|46qV&Y^i~O${naG zk+K=x#gXy}x^~KSug~J&xOFJ68?DjA>k%}b;q~Gjb>|+6{}Z=9-Zb|}K6+-ZpOC3L zKcH3?IzOm+74*n;J7(se5c_o(o*KLjU3g|P*|hN7;?K;&3ld6ikz+4)vej`_t$FdK z>#xrS7O;)at*>0Yn{gK$KL!7O~GVK`k>VUP6IPYn0|C(oR74vpZ z{$l4?;OFAoWyevJcFXB01(NyC5-ZNjD=@3o;??C>`DUQDkDr~XQ&dtv+~4o^>#o!b zx6zv~KGs<+J(MCPa2%C3OnZG)(YPV`9eIl{B9uP8er&C^LX0Q@J@Uy(5g1e$oT7oD zW5}r0#j*$V@8i+FC;)}$^7)%`0D$Atkh&Cz5KRe?T7Ccn^I|gtN(Dt%@_}I+!dH__ zq@j;+@3@_UjBX~{(WFPHlA8Jz%~rt^Y!tfl3B!c}rf-N)p<$ailc(c<*ipbx8`05O z2W`%uIfPSkONBrw|5C+csdW4GOyQVrT+|{g+oy?(JD_QC6h?!<23bKsjt>OB ztb8j3B~WD7$tbI(?t+~shn#KH=wJ5z!Fd8qkRHQEE*BPQI&QOw| z1M;Ww5P-^+2tKl<(tof(PMlDzO-F9a=ze;LHz9pf8W0-Br#FFWd_73cI#lE7R?}vM z&2l)9L54xf_Y_VUXt+oAz>U2K@U@tuC3hNBw_(#l|8O16)hT?M$s!Y}2LuTqWjT`E zMl5wX1qcA0XkKsTqI}^iEVQlVOqetbAfb*iGuCL`LQ05K*?JyAiOB?@CXcKq^oQs! zCE>7&cUGQKLh@(=l)~-_jjBYb8`uaFzy@_jcR|d^&}Eg7@1$=AZSj#?ftJWrw+1d; zdkjsCC(^J>1_fr?dMQp@L{R&@P0i+O70E|wa`oV7Vdv}S5OS{=K+CH5s2X-q2vF;} zbFuV!GK^0NQ8=&y+Px$pO1%w=#7XW;;R-2hl8l$baS1Vo!5Qy=D2sN#UG(DJ5IP`x zD6m4Uu5dP+4}V5oA%B#`C*VJ`_C>L73(vosK6vgY0A-I(86CevkKarcV9oI20#DM6#HVW;6wJ3;%}~_E?9`NS+rA_;i951;gj*ps!H6xrkLM% zKaEU9!FJ1E%oq*NPwE7~Dm_VYv)ZPkIs(4io|j>&8<0HK-g9HeKe3669Bk(#}tgRjOm_ zx|D4Ust?v)PL`hdkD+PjZU3{O>F-yj_TF86&B||U`hUx5`d6)%E8Nl9zkBv{)!NvU zTgRQZ&t{|Uu6^L;cXUne{uTFr?c?(Ej{AR}{YqS0`vl-R*{>w2-@u`YC3@X`p~QTw zde^6efhcui%j1|Y`UOj~DD{9jtZTwSc<8j1RERSKg9ez4@XUPG=XiR$VtHeuyTK$$?$DJGDJw@lQFp(fkT-|<% zZmg*atf1MtqRKgk2cV)1^iH^v@X2!{T0*8y-GVG$x~3+?8#&m+71*{qamrTe0qvq; zfK9eHvrxR6>{wf2DR*A{3MznUC!o%TDAhrPQtJ!(7e?GbkV!Ju{Y4shx5Vro$&jBc zKW?M0kG-YwUQ4^B7ZZffY$CH^-B9d(qAG2CtBq|8>3GbKtC&h+WDi-WWT(BG1Te%x zn{`A#aS$O>PzK-&ivtzmLcDp%7bVzmp2~hea!0qS1I1i~mO^oC-B(!4&Y&8+f56DyonoD7+UNN)z=O$lN|avn#`G z5O8BedIpUyIT?!Co{>dB(@5wz7TgZM&7Xy;WMLmLg?S|5K@#d9BgOqVre-8_=1->2 z_P^kxM(GUave0M`#AyO5<`^o9r(y#^*f0cU$--kqbO0cI;CSvn>C`Ec?923h{WLV4 z9#x(iD$pZ(tq?(><(=jrx1}KbL6$8Q^@xCtCc`JkQ~G1l2TdYpoY3@6M@|MJj3YQq zEEK~Kw%Ov3vN6LnLGV)gl#){&osZ7SO>#;WlmT2Xdp(Up1d|;%DZBEx2$-mJ17NvA z!RGTB`DR%RVmZbzS}=>l$bs#7_C~acB;YuReL%?flvab#ke5jUS6Kp4EcgRXVhtIa zXUZv@J8-OMnf5gFpn7S-&j~{CVV#suJ1?(bw~#b-qW<}_&WYNx(WzCpkn92WH?p$91XdJ1GQqnEy++P zLUtts8xKHRxSG|6%lC+#3?~Vy?ZY0R2uu-hLoDH8Zs2=1`ZQHwh0nuXrXjEPAp99f zXEHRNnqJAmsGCIe(1aTt@eK{3m$fYb^m}5H@DQ0nsE9 zVcv${3m_;AxEAqpFc;2t4Exd_>v|f$Fo3Y4R0|xYEg#!^^(G?g&MATI)UJ1p_g5R) zvQ0f^O%MH=9>q0j-oj+F8?70Q1FKCO+2)sK&BK1pZ{nIqDx2TkX&!s`f6#Uw3{9?U zx_-a(P?FG*8hTYgkzPVaYCupF)KF9uOB6)xp?3&^G*N>TK~ND80bA&ZfS{;=jV>Z; zP&zDgKHO`~o;|booHKLI`45oqeV*sOuj|%_Bu}l< z<9b&qz)fZqQo7{Z;(GU=*9C=?Us zwKqF%t=a#!%K6#m!@T$KSld5_h;TOl_!=^dpWoANrN?Bn0))J>=D@oh`i>a?nn3Sb z@8H^)5Mt?19z>52LK`vfX?XZ2Pa+Cjt5BI{Y!{v-vK(u>Gb_16HIZ{BL5wYUn3&BZ z)(R0Hz4UD`-UH~Us8iebDbi4;d2)Ong2oQ35SdBSq zbmW7`%QfxW9>oRivQ=IaWa72)=@mG_gNh4eKxSb7CKRPUyDYe`M(NArwte;|gaO|n zgU60L28{U-uuzo-CPG{Q2_$#`!{4^jNHQb|Z?d=OUGe8ZR#Zok>$h3eyI5`EvJs#M z5z>P+FhLu377-T-}&j`)zsZ+&QoZ|7rt zd9%1(Jziz!JxR=AC$v$^)~~)mh1;XI>y^*hyyos!Hr>yT#CPwa(~i=rN3fN3L16pU zq%(*i+@=#x)gCq`_B1~DVpQn8xp;+WM+1ieR*41h)Mt1OI0PS97`7LJ9^8#)Gv6KB zwuw~MsoP)n2(IKGrUB9rLb(DV!K@dpxSR3incusEs@_J+pxt4U*RHvaGw?Qr%J-F_ z)Z2#e ztx_*afw{a+7^C*HhY(oQc$fx>vx%Kn9ks^b<(Ia~s;+%Wz1t(V@BT@I$#wd0d4!+1 zVggi|U>ynMo!NnHN^1V@bBN<@pdm^u6~X{20NU6eoy0qgeQ=3Lwa%~UrEi^MYk_3- z`%TquO*OXO@Is6rV&h*$dnt2ESDhCqlB?id4W#{g?-dffw>o$jp-6pw=#SU_w-D

a^!Yc!^!~VW{bH2L{?0?&3Y5(3NxTm#&^iPB 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%0ASDlBr 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 literal 0 HcmV?d00001 diff --git a/src/lib/zed-ros2-wrapper/images/point_cloud.jpg b/src/lib/zed-ros2-wrapper/images/point_cloud.jpg new file mode 100644 index 0000000000000000000000000000000000000000..63fdd258df5d6305fe1c4fcf722233026b2de62d GIT binary patch literal 122887 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 AKM0`aEkno0(lIFg$G+FkfrV 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�LO6`zCuua?AAraOLm-u(`!u zTFD#{gcwvkenC{<1E5XK3*G5*%3%Cgyvql7=>fn=y>IM~SaR|T=`?(IGsA^X`F;d( zqS1-uw&&6;=k)C|9`5bQL!wZN3ny^Ap8jooXpZ_yyhyA~P*<3+ES^tbela-ld5v-L8DA=ar36`vF8MJM>ZGo?GtaryZx zq3~UObPF8>JtxC0PhT9M!w@@c$n-UTeZ8dR^j5LkO#xBbTD~l@lzr%T!8-Z?__9NN zHGb*)-1yJA_?6n_J>v(_o+aq?ZUiK?oa1mwBM$voFvB}>1Oc+?fVuZK0-IUE*k|HWy!8_oV8rYPOxqj-VAA*)!V<55FOtWjTeYGd31n&|rkZ-1@?$w$!Q z*%Pz${?%-IXRP|i^)?8)vdfb=di|;FPNR{IT8YZ8Tf6w~ypVXSbNLOdsOTA-{@GHy z-=t$%`P$4gtL+slJWX`_&5sr;j1m7DU|OQn@dIG;mWZn&o8D|YZ{CuBXVg7M=WnU) zmqiViM00}8mV}l}H%z;ivMT-S{A{be_j;olPk6G z5QD}ik|a;%6ypd3UXuIwA>eG#v>lKNg9O*tv?0yxT`j2<*?W>M3oPa2H#`-T1`w_X zfE?@SN%YyRUo3UreGZ3MHA92%<^p0%rd&@f!Qswd5kizWWxRd)0H8VZ$?dY&Zxk33 zY2P2R$XN?4qbS*LUp&81vBDbI8U2@gByq z7H+et*Q~bMO8=PAO((3Cl^eoCU`wjn}y7$r1CwS&<+U*A6yR~%W+7E!0 z%kals{vaaDj}SO|<#sJ5-seN|*ZaBny~$iQk@jYfBW3yk8&n zCBm(V_@K@k|8Lrp|K*LBu|G-9?bizi9{{Q=emIu?*Nww|0?D_g4*+Ky`X5$De&c@e zKN+!}KB~LiP715rP>qKjIn!!CY%FWO{J&4U|88IVA948q+$-z;^jR^+TmF}K&9mp} z-FC}#CG%2$Fsup$J+X})&y`ZLHN>DG-5 zCn(YOIY-H6M@Kt?!Ep(cJ!(r8YcbpzdZ!pM;>aLWuX?#9ss+?Z3pAI!PJk* z)RM}RgN55a;U}QnZ-4EtOCBeo{kD-;Z49i;|9Sa8U(0{~9saW${BJ)x1iw6U@GPOe zulT=5E|$l<)7a|HccMnVMUdsvLUCyLV0$`;+^7ubyV_dAZV=1U(D8VaRbUwT^gy3_ zlpK`Xczk6#A4L~SA3ZnyI^sU}+HW|k4e5Ade9?9%^p5_*;>%A{H<>k*nbrpgCf<;X zy#BY8YC47sjifP0rBD$JrbHQ#nx=Uk31i%Fh`yQk`JfA{m&2-HXnchKw4S-*9_hPe z^=QvK!EYblOcyAHOydMcmdr^4T{@zotIto^BI-dYQ<|<7qn;GlgXd#qzT)f~X7>DH zgF>X;=2Jof(JbS3Z#rSaxU9GAaY|;&tRK7A5Vb;8_5njYx<-pDQP#zd+?KA3y~u>Y z6;cm4(+B*d!4ijV;9$eJfQS1e1H-#U2i^DxgZ#W6UDp)VngxDGFwwz&Iw#?lC3Esy z8jLjof-3(_`Ngz^C;ohTL|yJva1I1t_DN?lPpKQ>l=kWQ35fNUVM*UZ7 ziT{sf#{cLgn$}YY8eLt*4gojP3Wno!G5QM0uv`rb7kBL#q(-#N26T{5YMjLV%%0At zzM#!gf(`P^?C$@9TI!XN>*gIT;Lkj8-4m{!v-2TDhLZbA&ti8wQ)paJ#!}Yb z(T17~lSz)`zi9H-Z>l${1)C9ZjaFo)@mekAYOZU@Y~Vx0lm3a{pDE;AXOQiEOYMAk zw;Zr^*VXscQLAGgvJ@Pf84^y*hMja&3ogEUM8Ms6{_oi-8sU>Qp$~WzS{2dK;3EV zW?O=kBdM)A7Fcigq*6{yy`*3@QoOi(2J2&~GFtx9@tjCTGpYiYRiU0=C79xf5pg1V zLMZQQ=QV*NYH6sjAC)Un7OZYwF5=GYKo`kG$x&g{$?YN^`a$}4WmvA9t>4Q#wkx4` zB=C=z&EHKg6zo>9{p79Q4Vam{OwOq~Yq3@0E!PrKFZNby)O0glCr-AS4+qQ3*rnX+i#Eji+_AdJL@4%x{Ju^a>#zBe394GjPcVV^?s|4Fy8EYB zAIoyZwDn7?*zHUGFqm5`Lr;IH*#K_X7wxrjw-nudcQk_uDp!e(+tY_@KS zd=02JMXJrW(>&>1I9OefsWwD4XeHj2-gw)gEhuPBp5*${jfqndEQp|Ork1>HbHioM z;rhx{rVe9KB>`X&vY7m`g7s3^>e`$;*o$b9CbK*S96os1L}dO`kf2|C8R2f|2BCY+%Z0(#aZM%&NZ->Hs9uA5TCZPP{`U6>BWbB z^he}Y3PI`DZ~s2Z38*ip7z*_O|D%26|6fnUh;MFqf$bH@o1K{Qj}U7lKMpnnEd@&i zi(bNH11U(dSeq7)yZxw)zSQ7kl%1!2*zob^8z@T7-=*HO*t)+Wz>l|7a2k6~kfkiV zlxl|7OZyV!tgvO(M^V3TkMEgazOt~g`v3^vDCBr_F!l))#Qljg>bosIo#>qF>s~}Q z1~vX8Iv5=8Y*vfz>ntRR=@)|&4=B9m2-(>#43i+J^$}4K3e3~l*0lkhPxD?%6U%5M zRjAqS->eNWdWqJXnV!5mGj}61-)It7wwy>yawHg|O#BDs#=s(N5tw6xX}b}=lued7 zuUwKvyih2ryR)$s$6A*`uo0)Zt}-!5A=|@`AN|X;8X=-+-q~%kQj1NFPaiY!`aMnE zlU(_lPb9pl!;coUxfE$>HS;ece}W!Mu~u=Z(eu`&TTeXzmgmLK!4Tu}(dDuf3a9(X zYfq~-ubxUbtHLw>aj^@C_y}@vuyCIjT1G1H066t~0E|C|eYk$Vd;p|B0PY{dLs!23 z;wGbII8Yk?35Z*+Z9W$@0U9uh)Lt_O4f}8(uT0>$bZ`c&3F-J9T}`znA_0 zFWGuI8?!zoTGV*Lo=HaHW5hpEIV+m|lFj}0<3D^YO)Y+z4}js*I^T^4fa%h6bLxk= F{{zSyi!%TK literal 0 HcmV?d00001 diff --git a/src/lib/zed-ros2-wrapper/images/rgb.jpg b/src/lib/zed-ros2-wrapper/images/rgb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..58de75ab8130bc671ba1e53c1bade160dfe4b49b GIT binary patch literal 151430 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�stx2l~*k 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 literal 0 HcmV?d00001 diff --git a/src/lib/zed-ros2-wrapper/images/sim_rviz.jpg b/src/lib/zed-ros2-wrapper/images/sim_rviz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cbd120e1487cdab530365b0f0ac49c9c314cb017 GIT binary patch literal 305434 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≥o%kmelcPmEk6v~ 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

bP3VnVmjj>-gu+)OPO7dd;s|7^89KedVb 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

LyAwFHKlpe#ZK=mOCgT-z6KV2YO#*N06lDB1 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 z%0A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 literal 0 HcmV?d00001 diff --git a/src/lib/zed-ros2-wrapper/images/zed_shelves.jpg b/src/lib/zed-ros2-wrapper/images/zed_shelves.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcb7bbda17def491ae4034257e08e9ed0189e084 GIT binary patch literal 229060 zcmeFZ1z1(v_b9qxBOoA1gS4P@x5NgN5=rS&0ZHiwVH1Lggn%H@-67H?CEeX!(%qZQ zU7qth>iNHO&b#lu`{LerHs9tOYp*ru9AnJUbIx@&b~Ojwd?+O=1t1{-0225ITulP^ z0d!PUG}LS8XlQ8HucKpN5!}GS#Ka=S!^a_@xJ5-taf_UsnvRX0`ZfzKIXMGABMS#7 z4-XF&y`YEymoOVQ57+ljkgi|9j)jRua^nUG7Y#WL*Z<+qRXu=9`H-e6C{<5tESKx^tJFfsu)amycgS@ZS9g zl2Xz#vJW4ts;O&eYH1r9JvTNnH8Zz&aCCBZadq>3<>&u8;7wq7#QVso578fEQc}~> zGcvQXb3PZBl$MoOR8}=MeQj=OZENos7#tcN866v+m|s|2T3%WGwzj^ve{gtod~$kr z{+%u)0P;Io;Q!wV`!96if^;FHpg>U2zSD(->Hr;@{@-MkkO6 zOD<}-PRp&bOK4!%k3mGoGk<6AJ88dB_TNXC&;KdPeh~JPt_c7Of&@+;1Q&n;$FrPQ zz?a#0O2aF_qwbz10kHG$5C8JxUvc<mwQ)OJ0Vhi+iMZIzDeH4_88H*Tl$Xez!rw z-^X_hO>;?<8hswl%6CQ|&RH2@!3Y_}LY1yn%-L|WdIQ8NSBFfK%sU%JiPqb}ki>3@ z{@R#K<_&3BG!s%qkpSQ}q93{7L99~|HLFk;;%Y!@1o(z3zvB{VMp}9C8xm#Bl}_v-Sc# zwjp1R?7S#`;jes#9E;7@{f_mpB$lpL0BI-&`0#5dpAPGYzG-(aPMDqh^xk7MNZ}{P zPQwGBe)` zu=Q$*GSd8y@whoQXsC9Xd|WXYAlZ4%b!G0^TQx@qNlF8>Hfl0$!pA2`H|jWh_sUoQ zV;DZaV4trl4_TQ|%CKlO31T{*%cEf9KFl)!-YzrY3*6@Q7dWxot28pirVg$2;Ni< z=U$e=5RuA4wUqeFjW?_;uFyb=sEd}(v|Lvr51gtI&*Y>r?J0{raq@sD?U(%O^^dNA zs(0Q|SErYY&n%!D4WLiT<5qiFWU*NsZ+#N%N^?ayOrh5Wk`gjQ;{CzVR~RLn=; zI#L~XcfX1{c6-S%TNPk5SH_`v1w82-$;xEa@o1*Nla4ftiHz*YPSY1hNi^<1{D`mI zMR$$Hb~!FY!TxMG5!)p~dWiRJyt`6uFuQ11f75d;g_i-u5fSBBvx--MMuxI{t@Wh^ z?0~R}@>zr#0>A>>hFXWU}p2YeEY)V5op%i2$F-X1)HUJEv3jm&t4 z6TzH8p&UnUKbY@aqO!G&FkBz+JPlQn+qj|FH1d|)oHer~2bm%dhXieClz+ZDz|k7t z#kJ&Hn%bblivMAB$Ez1lY1)=nV-7nQw1ut!Jy@6e!0f2vJ{KEwo)$3~x;Z=kWL)qG zch`Y197e>sf5{xXclqj8M)`a$*}F&FQ!>H6zCNkx&JN0!{;s@1+FONzM{i|G(}yfe zOadpKikiLW7@O6%JtF8uo|LrDYxF_f`M9+tw;@h2zueZqMSRB@+1;SlE|56!sP4>n zA5nG%(0(0RR2$%AN+p5w4QQ8Ncv=Xc?T_ofNnhiec+%ATX^0S>_?cS|1*J?AZ>&{t zr7Do&f|cV!LwK~&t*M~eI%SQ2C)eyYDy30W27gKYyxdbGN@g6{53&Pr+H9#R+gN?2 z{^=&__Xbc7yRlYC$g5k&<_stI`hDAsE`g83?_^%3HS`4voHeUvnWw_4aVY!y=6phC1x~qG>ozImgT3A?P zW821!PzW+1P47b>a?Nexz=oXgISfIKZj5{3u}aI3M^t6D7l^xmeL{hh&NSo`mrj`Hr=xh2P*ID$%(}#qJd_W<@RWK_m9*S+UhO zS80}UW3}yeoph&l<7qcFuQqd~1-D2X# zNS%l8^5p#&iPax=cs5;`>S3Kw<=M02yyQ`|bPc{tVUE^Xz+{YP=Q+-V<;aX>g=v^C zQ&=mC(_y|JiIT`QNpd7?+4k%#NY528Z@mUR#IC&pTA?kWr#k0~mykl(UhiHZMS-tE zfBrTP?-vUSsr~yxE$aPV=*g-}@Zfb*NMGIGw&Q;*6(WDnA_G60$bW(3;e2Qeewi%E zIr)VebNAiz#yjCFHv)95?&n%sRXoM%@Cdm9xD~=#FX<89qjjgNr~Ov|CQSAUNOIgk z2qJh_Zeb@9W#`_>YgF;0v;6dqG%)!os`$Eex}0rlC+ljMNv8fJm-LEE`Ddngl`Wf* zN@!N5kb%F&t^oB3rf*K^d-mJjtTj@yq#PL!rpA|yRs|phoNV6kXe#ZYP&9F5ztt6&ug+MY%Ol6GfDRfFj*(Y``mmdHiw6$v+_-k z`|2P$`D(~}q_xD|^25Y)H2o`JF>z7)7nY7j>YMS8;Ie$+cp))qN1T-&Lz*0xG9k^DqY2rx4Fry$zsN!Auc%u1L^L_=HW2i(q>I)cbRki(Br#$R zX713!yOl*LzC^Z;CmF;Vv`5K|t~gFX-_{Ahh4#cKKl~F5d*04>#!D*)3I!wxSwq_+ z%X2=_W&uaEW4BUbMBq_Ud#vrgW-qtN0z>kM1*zQ@36R$Rp3o1lXXfsKmyvJqT5+(_ ztZXAG+=J`~W0Jo0x3!H;rTO|Mm_o*&e=EAY_Xr|1%?`Agg?ceNIm3pPIcdb(>nW-d zGIH+*!{{O&6w$|Cr&-`i@lelYGvec8gKbTWMv1s>6t7u_$R06~H~%OIi7-PQ>7y{+Oq`wB5fUujx&OZu%r@voT=~o*TjGfy&0V=A` zpX;Y_2rN>ToCyo%G?U33H<@R>%*z^o48M;S)~nnMxH%QRWs$a^i{3lH3FGJ03qh`%$$4CCc={H|?~ zLwj$jM(q6|*1+rYGACtSHEqac+@&ElnPYQ(XjxaluV$9&*S_^FEaxXH6ZYv5AEl1IZm^)FI%)!CkF3@OY5p?(1|`&ZWKObYIvLjhH~xR%9x;NV!hd~N zD?4Ul(kv`~hzqZ}EWwpFtkw2ZRd#+_OmFhO?M*-9_YXANG7Txad(kLDt|#GuA^)F! zz@JpVf`4}_t1kS`g+zVE{Qa|{FN@^vubFp-41*R0yN#viFI9}*gpZ1vDW!Jl!e<@A z;<7~E)F+S`)H9V!`ZR9xu@mJ(cWhNGl>~ZblTNHXS)RE$Q;S^i@|2W2Bn@ z90$_<(Atd&FA>^*7Qw~T=}xPYvg00BQ4{%nMh~x}Ruu0k??9=3>%}s;kCq+vPT|gs z&(*&@T&1S`3Mw1>-+Gzu9k`Gq;pMv4*IrAM-do&N{+2ay*qAr(&8f2j?!~Eh`G|*Alu292tps+iTc5ef+v>}>%cds*n%1G4nXq>FJXvT08mjqr3LIXga;Y1(XFS01gPa8p9d`BPl* zXMufgpR8z>#=F^jt4g=Dx~W!HrPhr~cP}LFkXJ{xB;-P)xa9q(5VLSTCRZTNR*W+L zpIl1U7s`Z5`5`N-{DL_SnYU;kNtNcKeTVEPGxLcO$SN0tUs)3(PTCh zQl!Af(FP8!|CZUERy-n7BSTZ&Rw&|XZ}6CJl5K}0wV~0*^d{jL{Idi(1p>!^KZ~uV z|90>%58xL6^59<{fN9RZa_}z?zNfqY%E7-p_*V{oFa7*KrVFo5vkhchz%Spg^veS?%0G=B` z7^vw;G`zjFwpz@@SpjS8F9BFZ z5s!^2J$y@+j$`ukogx&^-O7&D5YI;uflqFl@tv!NHxq`Wct0Qefd6TKc5NSLRg4%m zZ?T53j=YS>I!m0IsDu}P&w_sGvH+864|)ZZKe>!4zdf*hS4N+;ko;q(Z=+$s&O=}( zVxc7-TX>pY`O)E24)^&G?AH`Qm+B1xYfQo1SS;D=`weTF=aN3_{0P->l6jdKEiEY- zHI-IM_&+BD1|v@V(e7?#>aD2~nz*QY)UQiCz5mH0O? z36z}Ou$E=uS&+Jaj>ES*AA#%k-<}nRZxV+X^zo54F%hYdu%Xi#lJpYZ$@GtIdTKpi zT^6-+X&G3xc{vVwhrSW+x+X^H{ZFYzS$2A}^}QyF$gK#9B@wt6vmfc1r{wCvI+I_? z%~)3}Hq0~A2IOR*NO0RT5!;1I{#Qy2mAUoR(R;5V*LvfGAvztlF`h z!;i)JYk~c`1(QpRtGqs%jW+J<*LfcSE}Fu5D$gaT&3PSBtInz!cqDY7>NF$1?+I@nn{Lh^C}G zcDYp>dqa#u5vR~asqrgdH4S#Mc?ARmFUHqDNk1)fE_-4gDEO$zK+jJWxalH@1_==@ z<#Gv>N$8QuHwfM;NUKz;q3X*f5>*zD>aI{fb z*;YW>;L?Qmf42NHO5fOorRk2fN@{{Wr}2`S=YTDZ%| zmn44MtwR1f#n<>{&QAML5fP?zMD8{CorF%y#oM&KD{(iIu!)PP zv6d2FXfXc3<_GXph#7kGPM-RUV+oyH>P~C+7%?DRYPnT_?t~z!>U?ryqGiNysXWld z_pAczGwM3$5K*u8VqGacVhI)oN(}S|#DZpz7D&X{6>8LlWs@u}3URe4$HI6ges1J8 z3Z;E>#~CAw^vy&q+NV70EpRcWl4=Ro68Zyri!?sr5}>0qAz=wJTiS17mV6o0$`0|$ zFz%_Z2CJ}s*=M1Q_+|f(OXJr3QF$at{=mzz7HRR`hjTws_zAI~Sz0eBqXs$bnZqY* zP|}u_w&`{lLv#`<*Vfe7k2KlmS&ntANpUG*Jac}4P3;@NgzmziQt<~qzhX98mT$uM z!NSb;xsa?Snbc=#hnwU@FCxc0Jj`tuWWMs<1XoZ}C7-VEGPft5oY?j(_P%f*#s9(L zAHY+g+)zT-o$D7o-OKld1!I=lTDwSkoQ@9>YWg=`(!JX*pJ(y>s&EAyznLAJ&D_wn z{>!O9#O%e_Zq99I4bC1M<5mavN}U%T$Uco zcZX7@N75EL0WJ^OLEAv9LG=?Pf)tGKrVY~sU(1$~W-$tX!g)sJ?1VIVM0YW)$94r= zaGh-3hH{_S-JPEF+>h+>D2`dV0)9;TuN=2ES@_7B6v*cNokgN9-! zv_!6!cq(hDJ~6O7AGL5ymVH+;%IS`%Du!0T8DdA_o)h8f>`#>bgxzOFTwx~*^zyTj z$u^w2y4V$~7AThL+XXV!q2NO| zWq=mJ^Apm%;cwZ~JxI@M)p7-FD$TSmTVJSBDmWWjcjYI-s?SFSf5`9;;HeOa<5A!Q z%ea5F|M*r)VproU%V`brcO(aijq&^e>YB#SjES}v80KTFxoIN#4s~r5hTGcqq)sO)G%3?*KKA*A7^KY&jZ z9>@95-QHE3?Z3@R4xwI|BM<^enTsnZOPvnB&Q5qfpcYB!EV3z<<(4VBd5_6&UivAs z?~mp`fKL?NS3p2=#jtgI*@45wE6oQFXS6WV2&v~5!xCO+XMigPa^#^52~97r&AX(^ z21divCz9eQrYPMsaDTAj2k`XX%l+QmU{U^kNT1)s>4vqI)-cKv}6MBnOC~5RlwthmIH{6(M|Cse( zrr)Ap>lc;(1tfy#2maOk-#S$PiS|$EUjqK)RsWrVAD-@C5&BP@_P?+aXVG5BQM2?j zij?7BnoXKq0SRDWI$Mn3@rnw3`*&HzfA1}SVt}F$SJV$3QG&!u7**xh{w|}ffx<=D zvy^=T+^LZPJ8A!(IMqoiU4W&J!(PN0m?r#Rzhm4Ev!%oyYZGmSo3*>zbX>;`x&l7K zTD*7|a;VG`5n#46OAj~wIi?u#xBsu)Fr(a`SA9n-a0P&2Nibll{5SSp=>K<~!VRo^ zWEFXl1-#EQM>hd{u9->ajyGq>A?x4&;)=RgW0Ttk2gRw?qT{auzBhx9KYP~M=pF?# z>wX@zZfMZI@iem%|5BeS+Oh$XCkuTUr`ql6j#_At@Fkix}-|p#O3-T;og8pTA zt><-gF-susnxQ$)Q?_wz{bfPi9{%vovyo&{Uz>1km9mY%RIJcF`bWOf|%)} zdhZ_3G$BQAEn#0 ze{>W-b9}S!wEt2F=RVfcgB`W}ZFPn;f6bb~G~7Pl)0ox2OrqX2$ZNex>xq(= zpQcdbGfED%@Tm8ib3e-3*|~AJ!5Bn?PT=LTSZhD~mn?Z;b2xv8As;qh*Y=Rn+`O8Q z6hmiB)zcm<@DOJ{5)=Q(XFrlWRd;Y`q4Gu;L?D4(Iu5J@HLr_wUI9?4;NSjx-NCD* zCW$twmF9liJN%m82-+{`Qk=U;q#p^`GpV5QL9{O;W z%$LP2S1v`2rUQyNuZ~DJf(gc^%U!@#PH|J!0o3N}obstU=y7b7jEcZUzWlY?Sn86HKm0>lswJGN! zkPu!&wb4nmudiS6!aI22(|eyd(b~tXxji87QL}9cInH}K?p}drgW=vSQibT_8|3o% z@~f!S+v+XYg4^J>yUgDA9T06xvp%mG(;fPGd42mkoz&s~Dq_c%j z1g4zb=6jFD_mKT@oaLqqz36bTHhZ2NtB-cKwKZcfmTlL%b4o-UB+ijOOQ73C2}zPb z36%lVytTR+>s4)SBit!{SG$7c{pq4OJA$zDz;3F&Oa6;)`1)4*;P}+_Fx<9lPG4-q zNkl|TI56cjYGOO?`?q**@FRS#=h8}5aq|euuQ7dXq7Mr47j{^Pj(HQD*jZYx8pbF5 zly78JaJl$=s6Cg%qJ5HC9JWs1zi zkm5yCc?GD8meRr2N53%%B_0`Ws7NF7J$=0Hk?Dy}$dQ@Rm4_NW*x{Km!>*t+VsqV^ z$jN+Nm>@8Vp4@S{)nv8(D$cNCEhe8RokwcQFDL*v74Y>}r>8#HHkTY;!E0vphww<+ z(mbx%`i29&bORJOKfe7+q^U)R^|HRzeCuL-u~aKU$}FusWYExfOqRA_1!bF7gnO-? zP=WQKX*iu)P@elK^}B|>cdl#AGLB|)I8zPFXZo^l!2^|e(l1x(3rvyNN zVVaaM+BR&MGwk=yB^oLFJVr~0?8;XZ`yx6FM}VoafkMRm)k&x@G zD1;a5MLStNMPCfsn!6a58d^5Qk4`>FWq#un-)jBnAf%~Okk?H4goPtWfnM2nzr0)o zn*q4@=!;^^o!8M5%9M*0S#*>$L!yyfV*8}erUDA~wuRnvl5B-6*79E{Sbta!4bY~1 zy9f8 zb1J)8w;I`cxesmmTxwc#1>EeUw5=$B?S!e13``Rv6F`+?fYK}Ay2uCkeg*gf1L^N8 zpub*OrgXZJhwEs%W>d{FlL+MS6LEBsV%|z!^hqVyWR5S0Nbk-wvsowF!E5H*%B7+4 zCn*#_amr2H4c3SCTEH$qBK@>?sjq-Qc5wN!Eb*K(S3|YtmQ$?AOkWFc8(JkjF_7=H z&d=}a;OY~9sdahU3-!0)zR*$G$FfY0?47$+bI>EX9e>i$DX zf%Juja*yY%W7uqu^%UPKK!tg%et0`izko41@7S4%PYWoFY{^T2v}ic2akP-Sc1!MV7U>)!o_$`HG;K{ zYK#9=gZZ*B8$7`wwSxecmQM#LbW}tfG3zeivx^TK?DL*r&2Y3u%~I{~pQ`-VZkGJ> zvyr^B^g=IQ%r46PshdF%U+90u7d+naT|z*<{R!XDt>7QHzrEH|j=;5;J=+3t1?TB8 zY@VccI+Sk~3L*fmD;52M>dg zKz4tZ5adOzQAd2%Av--f47-=X4L9BJp!ud|+9m&2~PtDQJP@Y9`5#xV^Z z=~p`ez45=(@Lkp-Pv9q@+I@+=0^Ss;SSo6kCCJ=4u1o%7q0#s#?iQ#mv$7{>Dc2T`1QT z{f@}tfrZ=2p@-RqyPmo9yI&J`il_!E6;EXx^9(NxmB7#*JVkR0yyi{ea0JB=ejT=# z`Am1~alKpa70{_8d0q|Mp+aB#@kmMdVvg1rI3J`|x{_PMqyd}U_->yui` zt~?hM%32HSX8qfheZrOo8!W-bmLGb&I4A0>eQXDvA&KVqX+Zk}%YpR{gRfx#$CAg~ zy-+g{tNgrp3F`WSh4lT=f_z~)z7N^cmlNwY2*rV9*^R{qR9e@R(QOJKMIrOsBANAtKSVl}Np& z=d$h4c-)}TuMMSr6S9!1q&61Y2&EZ)$>(;vG9;hN22^chENlFHxUsk@P~3;D@u@>q zD`+dF;d`pIWrM=RS>_`W>oW`eO2^Jm-5}$N`QRZdKl|JzoKnpL1ZWZWc>7O@R@hIa zAHNK&bAY!}HKHBnpA6*_zke^IkriYGO$S_0;LILR5T1F^okg$#cuK5%1iHG?^c&^1 z*Bpr=DCHwNLsep>Hxv#^iK*`dQXhpYUot>?(VBvvg7eoMdI<-a6nd(0tM&KkYyHmX z{w|Fm^n-<e@muWIt@SrStOrQ+wLO5T@$Tgv=SENZe?7oe+{JJD$GRken>s6NGJc#1ieM+OB zy2daZ-;ScUCC4#f?kl;wvMfy!BksM~QZVcDf=x>CJOiPMG+*t1S-TFKZoVU5K^UU)b7Ec^_Dd`;Wiq4Qb?9iR9{P!i48c#07fZuxc-0hg!eDlcy6(JRDi zI_fwFV+x3`;0Z#-EK$}ZP{hUtUDyhicHf%q~$TYHb$GK>X z?k3nxKPZ@IEfX29Ys_z*6VVq#4V939>NSGY{GDuE&`_R8F&dmPsMo^&rXX$Qwx&t zCKYj0kEeAie1YFjf1?~0MLE?s6 z5yAoVC0&*!@U2nAS;46yhwy}4!&abaSk(IbE4(n;*DA!9?|w(|`^mRIP<(PKcJ#~O z1qVH_vy()`Y5GAT>4osv$wT1ac$Y6D^w!7C{j=7d>AJb^R!^+-*ETC=WL;&j;%-0o zh~f;f%*!m3=nSgku0FKuAQ!R!;6KR3#9goTx`RCv&`o|<9KHD(@nJfUv>Q}bugEDD z*ZsW&IOjx^s@W%4K4+q>f^Osk;^qwvkQsHq^P-xVlVzZ2`hY{2aV-!wNsZV8TgwAB z&|NQcu;b_d=~xDVJWT7i%ul4FY6J(RFg7fv{cXO@D5!M@2j6i7 z_m|;I!^HYeL zUA?Z>%S<#jPz2o`seIKnc<@~??xPgV@2_7sY~Vp!o!u?uwLUv50)L#C_(rt9=k<&_fT=}_0Vs~d20r|dr&oLMDM6Z8WcQ?Yx z!bprIia~7uJn*cH1xWwKckRpl4^q&1J@eUvqu*Y~^W79iRG4ICDxrOp-91qYYPq%E zdJAV5f=ba}K!N!Z<8&~7}Mp59QPEk}5^l%q;h?@QFyBC|+H3w^MC(nLo(f0rX zV^-t$2B)B3lyrN}?gkv-?yjnvQCyq$*C0IuX$;7OHI@#8+rD-{d!FpHX!Kjo9d>*V(_*sBI%zy~}_Cuk3IswuO?R-IjCV2iH9#U5W zL)`v=AWQ&N66yx~%~jMgN}sE?4w_yvDKJ2~p!3=mPYw>A!oc|AyIAKt*38Kpc)&-# zE9{V2`-vamstxBKiNlK+E5pXVBLdq24VCsr1-Ps1W(9T+*VVd(M;k%W+w=B?SQG>nuZUmDj@W zW#cLh?fofl)R-=Z3vFCi5sorlGT`8BJ98x;mfl_N&|$4lKnrSJ;Rg4&yfXo)KKLkD z6ozUHZEcN^!LYimlAe~>8GSnGh%uT-A6_6)d~M=)M=f|nknauhvKN%SXibk9s|sP- zFajG8G!y2wC7Udq*wUP0Fg^aTO3f#_qlrN_2SKzHao8YH#1*fYv%51UAlu} zPO4tBE&c1ARF_X#VbG3L;Hhnk7-Tm$>Q;VfPoX7b?L!~y*U2b)o7-4|J)8+c!uK8? z!>P+nXq~pNm)TfA{biQXA5jmqzFDH5x@kqL~MI!Ovo3 zEor6{*1TIh1Pf@>4w`l^G^tvVt^fxaShxzTv2H{JJcRY-4mgj@!*ji{G$=s;^kESg zoY%na0id-x6?635x_REpe+A$wSihcVOsqqqOnwe+XC6JNI|*G?z&^WZ@e;O2++=-R z^9kp|1bmPzO%%26Nv*4KoibRensD6cleq#+D``R?e&pc770yvMycKZ-xQy-Ixp4UM z3BCl5&N%QAI;_IZYxQDTckx6@s&y%HQy)|_m+!CK3I<%-c0~|K{AF^9JFcnVT2dws zM4##`(9CdyIrK8T*3;DpUnk26rKoq1aCsK*rEQMZ2Ab5MmG&@=B)2RTc2^U%$tNHr zp#4I@dw0h=~=59xMNo09OVnJ zJGMKV#KW~53G0_F6ZTH1vZuW~vSqWj(e8r^3r6^)h{1t6Fe&)W;Lm{J_>bO4iP-~$ z#q!Ja3?E|&iF73{DpSC;tg33y&Zp{5hcz{Xl6MjC!(pDp3j}E51YQaay#dU%mFW?& zppnGa#W~(C1oHu%9XL8{FUcaNDlS<4l*;1u_bioI=;+iwr&xfv%9O#zo*5i`es@$I zx__Agn;reGmc6mM!_#m1vR`(&Mc9BWzNfgAuYvG!uKS*UzP;8fL3N{4#fJT`(c^pl zf5B{aH}5F)>~avcvjJL8!c`OPVMRR!kXe(UH@>B~75^CFqmlS~wb%G31E$dBXz4g;O@8I?OXf}XAKJ8-`P;m z)F8@Pf#@T;mGZVN9nG*!;fUIyZJl#N(r2X*&U9%(dZGV^@4*0#>TU)>8+MO zE$9bSmmm#vl!(Zk38&l;G>?8l|_1U*R80Blz3EmEH{n2h|m4lMyaiU{Z~z629Nl2X7R;pY!jrilo5 zP-#4Fv7m`d+JpN1$F*ob6n-3mIOoyC_6b}?{Bh-x0z2EHzdSVkL~)I<_wtXcpNRiU z$M4hg?|l3ZkSh!6M^UmU$oz z&9_pJyB_6mpe@Q^X*1-iN8#)Ha}to*#&-t-xsqnEXVX`J8`Z^jaX zp~S3`bD7_zg+yROs=MoWYFMM?vyOLRu za5)Rpn>)c;<&`4EAwF4p>l$u!y_WXYq!sl{ZD$f99_|i#$@)Pn^Tau9suofhmZlxV zAG}isdAg%5MV5jSg$2#7&pBnvUjbBQb-U1It+&jISuBOYy=;r2Di#XXr^6W-eBO~qNX{6K*JMEzlDpM_^ zZo%mXn+rMy>0<4RUV`}^%wH#1OZYjvQ%ESz8WRO%kBrwexoh}Ol+vRT%F=gz?!5o9 zLLZ_y|47<;4z!#E`e4jz2|YAa3njb)+RB};!1qN1eIv=cBw+EH9&`}ji`O}$fwU&O z%X7-%$cgnF^k=HXeRGHX&n?N;iN6_#aF;RLxPCl8K(sAFl@AM*d={=dRBYoe%G|m+ z|A9=^aKDfeONuL(ngW6!I*?IbbHRl^(oMpX$KBRkCd{{(f{@0TLKZl~m-WqrP$b_K z%!TAh_YDT5nXes}-&eU{u4+0q6JC4nNS1^lB}1FwhBV8oeQs1a#AXuglono`bB=7U z*HY)2(w?L{HBnkD?~+593V8{ZUv^q+T`xIr-Mf~@|Al5S-wOXFw{A-~n@mR(5ENpO zGMwiy%`}4f@z6ptM(1^ikVAF2%u;}(omx8<4$1V?Ub9^k@n^G%;L=T|VAh(qOlYJi zzF~1r*~`P*cL%>T-+s{l*4HLTd@4wa1d>?gvN+*&&mvezrgG13^mX#UVp)4QI(>+i zR+K_c7v@cA6v}&e?&>%JtgQKt<%4;wQyz&#n+gkqG6Kd8YY~0eW65wyr-_hM&)eQs z){$Y;s)$Ygnekpya-&rr^Mds3-ke^76HJniw>2joppfzfp<21Vcxp27u2Wn6{bKVi zCvbzU{LQEZ-f&X2RD-;FcifoSAz>!A#WMe%MohW0%y&}nba~o#sn6o#%FqQ!(C9^& z!;9)-npDcZgj#f3-)>8J^iD>Q^f;dkia)E>v`pu;onYVj=4Lr|wcfqU5en%~E8aw} zeRvhOpqu;sc`dwQP)AOzJQ=iC9sB5KK0|h<_@b|^kKIW#hCIiGx$>BLCY9((NWaOh z&V007__!q(P;!BEJzP+oBD9o(+nfh>X20hkYmXrc#egAgq2hZ3 z@0hYD` zCiYftu2w;7fP}6rzN-++hn{t*3hR@V2(&s;p)@w{Te%zI!lXV@T|hEHSZ)Zb$lcb+&XZ^xo+PQN&TCy8}D@0nr4eBY;Fs?ML;I4sq8@ zgjr^Qm9Br&$kEBTJUB#m@s6Zi&f18r>4(jC49_fS(E7G`-Q~RJ23S(UY}SyOaU=*J zvbhfiOh@~ZI(cgX(JCLSXmy<4KGxXX9C>48ZVbdb;ijI)wZCDD>^R|U&`RWFb6EX>T4dDTVduS$Y{W0CG+ z?@WUw(*l)3yc=*r(Dw6GD{cwk^^6Q?rl}U~TVs8GBnRB5aiR^1n^PlwiIgYNcGtq? z{WjJXr?OIwY*mgkaS~GfK#4O% zQ*rY?Z~joqH|=}%OVLY$^)I{|8dfKgi}xs+(_fE;&rBOW$8EozjNM)>9JECrl4def zVD8D0V5y*WIA%~1G;^7+d6!a(bmB?40LrewQXj;s20we8;zVV#=>;v@DBjKkT@Kxw zs(f~xefBX4la24lbm%QQUALbPNoEHM#u^q71aaK=?XmAgv5gDtp`;C?d!G@TnTCJ2 zJ%5C6oW6^Uex*koLPAUMO<38{szYU<4SjoLpBI-9w*q*2jn;<%GCM2W2cc@xNKlT~ z$Hy6m?>4+aJ4w**NrX9*T$-JazB&@Y=x4Jg6fTSC5W0V((8sn7I210BrZBG@-3bZ1 zj3FhWD)C6-Ky$Hvw7R_-=QijlZ!E7B6rru%%q{5p+z;K1tWuE9efJtN4i2oXGaWX% z1U)Ay2wi}|gUV))R_e~lMuq0Tt$g_EX5$0pQmc^0j59GqE1cH>vtiom4`0i&c}$Jn zRnf!nruBA3dQ7P#GQziVPu*5Jq!>k`{kKO}1<<( zilO93cFPpfaF@~b;brHW;;uHV2hpV>ZuZO}>9`@pdx+BYy(VjtYpkj2t$L*kZpW!2 zA=$Z_JnlyFYCD$cXsBEYZf=w}RK;UvNO#L(^C%>?=Sif>6$zA>ahJV&p^0l+AKWNv zBS!;XED9y`pl@4d(!Uq%!C8SaHNVy#$}iYvv)o?tmwV059%Vz4aGE8R>{zyS%h;iY z@z_g|jUZxlk7s1z9y>0|y?_ce3@d{WC*|>vQWp5l%3+QxPT?rePH_;Wrsl+-%^%CY z+&z=!=cE?F^;8B!keJ+sC-E$k7bA5;L!1d=yX(vr)7Q0K)b#>low4IS6&&+~&;+DB zpxP{8?)gISNJn-be9a;KJ}um$zZn1$Tz3@UW&%A7EX3hr=P|(jlR6Bh>+D8lyQs3H_sj3`*Gik#-q92iR9AgsYe41RznL5^}x)FYw~M3bpW zm&Ckbk0Zng4oz^Uo}kf4Ov$yMycq6`m->4DcIlLGHpz_$)shP8(8phVEo9!_wWXPo zWw_p3_*h3%i7(GIwTw6&a50L;mqC+nrHYrlZFM%fgENw^kM%?s=iGF*Cz(7D80&LX zWj+>)h)(pbE;`Iu*LK%b^p3z>N`*aa4kN{hN!+E`(Bq5nAj&pB?%ReHfEe3BlRp`K)MAUOp6X&0Y0q2L+;B(Wxdr+u9vMsi#v$EEEUH1rN{2KH|=Vq zN>)oE=S_nTZhj@NxlfBGQY1!X=ONF)0u2~K#tc2Xc#D81BA8OctPEoqx)+Qey?a1z zd)jwx$#|xYv&Ec*qGmF=Vosqcu`x_#$&QWM`ogFQe9L@Bw3UjPK7Bbe?M{;w3jT-} z%MNVkmfqIoqFST=YJN5t)`QFcjFn*!TAhpKSU3Z+&PNJMZ!G(jB>44ge*TwKjX5>^ zc4EpglQfYZu$z*5?ma$my#hpc6TyuC(i}(>TnCpfUIubx=Fng6GZl9_lU&?wKQRncj2wTxa539Ff zs~w7sV2$Dy@B!Vene;p<6Xlg}^zCmjFE=&E80VfzK?Q7V3IXWJu#9Nm+HFkPo1Zzb zx+;1Ez@0(NnhW6rXr{NP`g8G!$-^F#xf^d-lERtL^%qDC-)vg(Gx-Tggw-GO95{5I z*T!02zD>RYUXZ~V!k0*7h)$&GV4bK( z=SnCU6XWlsM!u<%FV2L1)`s;~A&gTmw84T2X5s}{@|u@B{^s2v+i>Cs?x*mgIwqqX z8HRE{;wv*)l01GE%I-lJTufva0<8JAy1GZPZydDflGZA?hdLFR1oT_!9d5HY4@UQ?Y!CSRW^ zyd0c~u1e1k;|kkW^_KZCvT%M_)Arxkd+VUMwy$llaSsq6Xz<`}!5fm`?(Xic2{eS@ z(6|#IxD(t%aCZ&v?yi03-2409_q|g!RWnsH|IPPDS3#fM`|R3h?|s&K*0Y|~?9r#l z#m5dF3!r}@_;qXXIe6LCb3lqGcZ~hv%maY+84F<(m>FTfU4DF6TWmG4ips74NwdT? z5fTD4pAMCePJ5qfFj^A_g6^Fx$x=7D*D*f_xbM=mu8f)7#0Zk-PPt$PGo(6^CV9eE7nSsVzL}mR zJvgg+k;zYjHEoV+mO8bK%Nr1;vubVMj&Ikaw&wjEW(`fH`b$UgqbjKl;k)al#=z81;AwHDr-)1|vdqo;rH$K&;vR)B z9Nd9Sf5+N`Hg=&y*o(YyYve$%=7M+jK?_R*lIc#o zRqm&}U2liAF0eXcQ|P>Lzmse_{Khn+sIa97^%Xes0M6JoAQrW03ya)f75dQnIYX=2 zhuG8qCNTgEVwA0Cld>wF6}V#M;niQu<>v8RQa8`$xPC6EQe)DcRq#9>KHH`_DL+mdL)SqdO2)aJ+$ z>p+kpa{K?E7t8N-hR@W9|8m$U|b_e3@;tSU^erP$ycy@()F7=*hLk> zeHwoF*6^K6AXCqfpHy<*Ly!Vm8jR5OYSa{DRNv;pvoh)G3U`uzOXOaL@tM=+ZT<%k z-|^CnR=ACCsm-~;M}Yrbdu&48Fdv?{jr%a~Ww#}CHxa#hBJvd;Q21b4e<~Dw!ScB; zRZFaTy*{=4`@*;1lx}KEz87o2I`vXTcDqR&PX*3&(?dhc=apv8&>ONv z8sj2$$Xa#+2Q@*bYB7nY$8L*1c}^4+1PU=Q@p`%JlZj`NTwYBl-NcX^RDIX@qH(l8+YJj z`ao^%z7lmb!umEGUlZn)8ZS{#`#OMF*3ppz+`iVpKx{~XHEgoE!Y)5cgZ*}-`Ze+n zHYuM_K=%)_0NW&JW@CEqXlY-0aYB#p>5@z5n$ z<~o-~KE)-nNpdDMk+*3E?|u70{toxuY>Q2et&th^drNOu8Fbg8cx1S3t4e`FrOgb@ zN!no6;Y03TOx3YTq=BdsVk+oa3yQ?usHM!N-2q*)K`is2e@h^h(re6h%{Hw#!}8Rx>-qsZY@3ZXcC+?nclh%4j2ffy#t_e}!Jt;d{tF9pK`YmHDule;pcP zq-XQWWejdod);qsUa1!1tk2kv{g85WY zU06NGwCugO1Cd%Wf)ha=L(K$7)NZabu-f=d6~ToG#d)@!S+n;zjGxJ@S$^`IXOJSi zM}acJF4D%dA+gwmtO$|ZFUZdgdQ<_1W_pY*1XaJtnL_M zF!nCf&3^?QN(IB=dppkpz=G{&e}SlbATh8I8>}}#cpdl`9+p(tWtTzMsNY%hN3N3z z0hjE{VfT--hbx`OOjT)WhNy)xXYKmemjv0nhdNOYDLOHyWR1hu*M+S{ zL)ruL?9HAHoBcEbowwsWaJ6P8NDUR%rH!mi!iwg zYjiQS;{dP49DsTiIB0V7pM-%3OP|uy_T(*KCGACJ-wo!V?w5#;gP$)FU=KWgS&)Y< zz)-S=7i3cUpPy1#Wy8D&0Xr%k1dT{Iz5)(jV(?jl)PLV5;D7i1zvtwa!vBMHQo%|O z(}VnmRH*#-TAYKX;m3u`<*~U$Mfpw{+x;p8K|1 zwsno77aDY+Z=t}u(mR}|KXPTi?h~a%o*42`m&6_3BH;x%BA}mI`DXRXf;^n3iSi;T zL2*$GAh`Y=mHZm1@6h3_CjK1xr6(M~KPLtlq6yj#-Q=9(vI!?Z;NqXiqKYyazK7EN zttJt+S1U=Qj~BHUW9u+>MqoD?scog51m9ZD$|!-j6OlvTt_%Zq zRUtq~0QRe4en_947dz5+94FB`t|E%SO7D#yBw3S=PE1#c0_1(r*1XRA!dRNG+N&~j z!}3wk!*^6@YEfUBj+rvoE}j5Z4+2abLxnyqUf~YQ6s?W6k&B>KX!3*|Li{hN(1yR!jWCWZ0j~0cU(x;2yxnS=`=Yz*DS49kW zs3$)k1IRGvg(N_qDZXZ%d?74CHOAzmBg(|SiPp1ZHMC$dYh3I`#LE&n%nrcw3andx z1eia0h7C)c`c$f7taVciJ4?TvhjvyW%)%#O+t_1S9oWYm5vP#fRrgx@u8bj(5d$NW z!UBcXT9ID({$CD;L^@aM9s@YI&m!tyQY8pf3jPh{d<-(+z~?%*2^{QP7h%jrRPby*CWhRnL!K#hjh^q?fP)a=5rkJ} zEq|%ZyVs6Lu*p5vlwt%ZZf{Zmo)BU79gq=t!P9XbZ~(cw0M1B1fUAIKV93x*XkzXP zP~ZOjwbU~uiP7`3A!H4h{GNH8#t4Hp73UfO+VfY*BjQbM2QN2&Tg6KET8mmhGr&sz zr=5I2MIX3blW)?wdI0dmeob}kZQjA2l>VWz{#Q%DitU*45rmQ)lGok-(B$VpxO>;M>WC-XPIZSCmi8{ z+Hq=cIR0R=k!hJvogxPT9PJ=-QU~$(?w<|T6zolNsBV?^!Q*2nTQLH{{n#(bnH^X>lBS}Q#gMfgU@Xkl@R`W8A3gWtIyWp98#a2;TqVpqT;W+VQdf`lfO&g6$2bJ3G3KFG5>GY+XW4;#HwgD#AR` zZ;B+vMWm#;dWQ;y_DYj5DUx`;S2AOqnU|mEiVqooW+zar(E8Vfs7&(+y`|PGVWqM7 zoF+U-oLW6zsN`65QK3;7_)!kuY%h-Ra3Kc`=S%&VcTrcmVJ+f(BW{g;FD|t<6z%uG zxEbK@FM1A0t6q|K@vx>x*p&?z8}ipR%R3gxBz<-ED@N#qjoaVWC?Hlah$q9yRPbf+ zCy1$E5n1GU@;{mz&ll)@;Rr{J+zq2j+)41fWTx*k#Hl}ji7wbCRFfU&4^R5t&!i|R zn)FS>(9bX=-r4SxnXPZ6ttGs}$;lMzC(eHOB;}lhb!_1eV7MONEF|+C+ zW2;zA!c%+=3<4`%9y#zQSRQ_xhSOyUN%IVfQ97@Z>nme_e$tEi(p<%UuRym{6h`r2 z-F?k_l%q^twjdma*f^bS#Ey~vY0BOiGq$d1PK)*VaEIw-QVgEfxsp1ZhCCuiB>}4F zQ^1QS9p`tav3Cz;4A|0e8e>_0#Fc(5h-jE}g|4l{?12lE=NwOs6rE}oW&6EEjsNs- ziQ#Hz+RgV|TPi|MQY-T2nps6xFX|5vrH;b_e$g55_g@ECN=ll9467f{ae z;kFjLP;Vl8-y&8#ALecmmDphM<-73R!zF zbp!GDSLt21BAN??Abm*z0CPXl_pA$M)5iS@gntE-(F&*8CgY&omlP`dc4nHjF*?)9 zw-f#kC?ns;iyvpI6Q5}pnzFMuP;RPhgsZDwpO--j#{@0Ghs+C_qnQXI%j0o($|ney zh2MM{qhp>m2oYYs!8C$V2yp@W8?#eiY(DwBG#Vl!M#0S6a(>8M(Tp1L0iV3+81iS$ z_KI?Dy}SW~t4TQ=lyzqKZmL*w2hPkF?}`;c^GL-op=3vIP`uAIKI*Tq>I;(6S4}EW z)6wF)qm(bpEP1suzn@zssFIqK0m!o^$og-fj4quY_5|`1nw86F8XG}5c$wBhlpzvQ zMmSo{Ycc!QO)dda)k__Ou|I83@eHJlZHvxDa|VmlY7%5T^%X`hIX}ecf+|x~-hc20 z2y)ZG%ivX-!@}>lOjjmQ;kjP9_I7Ld{6^)v+YvIH_g^9G=Ov=E$S%7@durxcKa^(F zw2@j6OpW_99p1W$VG(iwdlfifeiakqB*5yyXFpV3UVu&hOM-3oj0|!&kb^!sN|^2T z)U&JV`-GmVfGaE=y5E(w71htkDJlKIt#L6ogh&^k4)szU?{WgMGjLyOPi1WQw$+2y zT(bYB;EA>Q$cbV{kwY&QL9b8jAZ{vv3{~V{R=d;Q(K2dDs-AC)_>^1mjpy&}k1=^9 zz$EP%RcO}kPVwCkm%JfL{95`u=5~}zPS5+KAj!;Rr^KOj8y%F5-&E{B2!a7`sk4K; z<7%sLHt^X&4vHc6HAVR(WZ$%azc_1^KA=li{|#3B^Ve54@jb6MkzUKck>A@phyYdh z*&N;VelYovPh9vIQplRiIMC8OaAQ9KzhveyXc%G%OA=N1kW4e;#B^wm*&7jzXmwfG zRly@Zbt#5z84c+QVEHQLrpUz+JxC9S_QKSd;FiTs2z!Ct9BdLtBz;a~8WQjE7LKU^ zy-{th4%!vYIka^?d)d-CbMmsW)i>-LCPF}_=$@aKdx(hv*qCMm zo3|?;vu_lo$6K}@XH1#L=HK)mkwT(**V~?C4{|JVpJ&I~wn4odgRNIz&EXSihOZ@*D;_Q&_c^r&$HkdUxL%u54! zL;7MhBPq!=V1sXKv>#Fc(z`O63s^g@0&wB&lG`N7oR7@N4Lm*seY&$XzPfaaPPsk!wlQuMLKJ1Lg(CU6Bv z9|Ol>6SWcY*?5#=NjD+E$|?JCmx;!OaxNq$-v=>|<}kTxnpW9r(L!jrkd)H-Ad1$Y;WE@8WHJaz%VuNYEqea%u^88Wfd z-O{tIQO)8{(wsfA=Mxw&R_~OI<)+BV0HVG9mS}3h``hm1SOCzoL4}zHynA|=8l8uO zQ}I>I^Vn5r+P~W=i?)fpOHCd&3DAeKiy?3D^Hl!+s|kFzo`aY^hW}Lt@$RE(GN9JB z&v>ERUrjXX5)aquYtcK~mP|;lf6+J~&h&eWI*Xmv8PptFbk_@#Hiq2~Is-~WuNMRqqSdAU-T1{I)9N>g+N_1~1+&A68|7knmE z6rNHM%&zaPqY%6jO{3UQ)zg=7;|x=Btwi?egeCpfz5lc7E*EAVPRlPz7Sq@2$B^bI zpTD<#=y#MJ!c>09p!lZc*PWmXk&Lod+z;N;HkN1)&Ot;RWN{SgTAoxAyQe$7WJG== zj+}9jXGJ*o&&^t4LA2UvYiJM{9d7ik3WA&}Kd_MS_!hV|InBo-6M z%k~&tvJfDnU*_|&5}f|852AJuQ_!!~KSI85@Y+JChY#ClNKfhSj1hBuHs3TX&@H; zYYQ;H7$F<#*4~4H6OV0>X9+JA+YpP_w2FWcJLDT-(fhRiCPX4!o71tKp-FoqV?#3p zTfq(X2!K*y<gOW2(;_3 z?%^xETQ;S#rWTrw^StQKi>!a5d5~%x)2{kQpuxQJ7p8>Vl_QD;8Gct~wfQl3Um$3B zFJaOey};S+s|;3shfzTW9!ddITml&0n|NfiXw5Hv3*+mMzLY23|ELa@;%lI$e=c#9 zzQRVxdCOc-4QNW6g8TmhedHa|()w=*%o@RDTfJ{9YFc!X@UG*d3cwFU+0y(1w!=CL zvuAZw`@%I=dKAxvb`UoTlDG})Xn!R6PfNW^Z`(OLQkx3-5Yn`5?>&S3aw`0dAg*F2 zFL;@^qKSW=DX_}g+z!q8b<7QtHv*+6^)t_o>YK=-pzZqz7$>-p&(}PDx$I~DAq^Yn zzC%}dCEaAqJE-|7wvJacuUdon`%zFxW2%d1PRlz1-73)^@?{w7~#|rUAeRq zpw37j^Z)b^Qz!9qHZd>e-l|iVW)(6g*qZU->(SvOi+B35sWl1>pZXlde5 zhn1%pxshA>~I z1bwsG`{2^R|DNL7s*1$v!R>t6xc=lU4i4HqbeEaz5s!T=Hy${ze=q7Xaq5qP1LsnL z(CPtgWl{gxMQYgHzV*{5 zqtzEIo5qm5&z!97SHczO`bge2 z&_@H@`kcK5-~*Wcy(wmy7~s$T-LGnH0NcM;`u|k}79f@j^95=l7CkdbS5jw->N)ls zqL#D?SviPA#mgbOzE9O+%UL&uM5{GOL_9w75NX5~lLz354ZEvIfD~M8L`uYYEWC;> zM8bHneDMy>ZFPllM!-AqNhY(3f)N`xSfYM{``sLOns14GBi1{&%nZ+cW!|P{(iShu zsSnlb{tuP6Rs(>={-a1yc@?$8yY_&k55R`kxH_|Wl>lqjcI$77aZbco4txYd4z|br z7x3n{X~;{Ulxd zC`j!DsDbK`Fyan^`-;DtCwMM!d1CJ5)=Q5Z?!H@BT~(9dVEWeb26obBE3%mJQsBF{ zYd!H9b8?Wa`&RAP$uuQ!W{zv1#*HnH;a0sQj;DJhh42+*kq#>3Nm!F@x?Iy0y-P?z zIVe#4suqJx0)Hy|lWZ2TdvWLxAq)|%gyeBquttu2?KCh#zvh@t#*^W@>Isy3`W^U; zOl8kbjqF_}XN=~Txzg1?fNrd^hF&OQrB_XOS zM@ecum1|wn1-^E4(v?rwS4IN8CoYb`gM&(!5fyJ6rM(g)0eLd?f*pu*P%l&zJDSZ7 z#&2$Lgnk+)CbWvhDnL{>C+lT^7e@~GFQlKj`BktDk z&lYpFMV>q1Zs6pp*pExloI+(CLaoRZQ{=+2EDts2-wa^rb@O@8d2mU2llB$%-Ilw^ zK)8a&mKD{px+efuScieP8h9jzk0bw;c0(9B*Ae(%)dp=3A+>CO~i|O!Gt?5eI-SYJ>kVjnTE)vM--t2u+ zrED4yH}3|J!JGM7;mJ>}`5xkj{RA8S2=?9~*24st>f0V~nHM*wj?EnUuzCA0WaTL4 zQolJEPJ0e~FLawURb3m(vTC=)a5CrHIvb^%0Kckt@Rw&|D&5K!?yPsx)cPblWw@`Z3aPewrg)M6iuM*>y6GgNM29j}WTiaeR#Z$mR}R z(B;`1sh#`ebBIrnziD+!h2#AY1$|FKNnHNW50({QO&kDhQDt*cfime?k9Ja-M+^L3 zc1aM!TUzS%>?8Kkd@H5=8CTa$SW#S+8-KzUul(q3?6w zYHmAoccb&#QhoiPXKS#S1^Z>ot+5CLLfl2C<^@lIHtr6+Qh{5k^E$M-va0{5)T;`o zo!lG_cNOT(5aUDtTq=2ZK?&dC$z65Cf%^@HZGo7f52cn+A=zTpgyu_vKmbz_v4E*} zjzo>%G;KP6=-7sTVGLu&*?@oK?*eHv$>m}MUx3!2#Vvmlwk`zepjrg8)oVV`M^Fe< z!j#1psSzutqO>LdaPc317@`1ev?BQsI@sb>Lm>EV%W+xw638JLZd7$ExB-+d9 zZy=)rQ0NiWt0jrPdugRwB3Hf0ddNY>C;(rMIXwXqI-e5K>>X!m5(R>P5~Ge2n7IKt zno|H3jbbc-8RN*5dpGbV?__T6YK3W78m6Aj`4ke*NQ+A^e1Z>$vgDxj+^95`=Hh|9 zSV1wSLZme~YH(#Vf1NjCA1?+D25CK6R38XK?q)?CsZ1`1LSaa9&fbkeYP%_RU-IID z6fZZ%`Of!X%@Lq4YCZWsJ@|>&XZ3te=8%j8_)l8OnR<$t5yc+A!Dq#Zv*hsB(Ti3` zfUJS%GXvvU|9wq!Rq8n*E|M!eH<4_=hXIAna@5w6`K3us#@tUJR4%ZltxOg~LAJUI zhO%6-q;5YuG4vT@e%lT)g`^c1)z`}Dymbg2Xr|zXM1yn@BAkzuF_^{p!~3Ts0sIar zlj)BR8{vXX_MX^l+{goXQ(PtPAnKB(jYJU+AFDSCgh19FP$AKbjY%8cs|R}T zq=h)Yz5m*Z`l`Y^cLJBa9UlY=(9qK>t_?mOM~2i#`cijk!0Y0c4=rN9)K z%iTZ)gx7K~$nCRNc?RiRcraSe9O=*d?`Py21HP1CKz?6*s$M?(s`9#8!+3}c(+VHX zYRt)LD2BJagGxhJE_f+J?TQRLQ)O2_=D{`P3LnmTsKMnQ>iwig`MBb}JJmNn6|}MFgt@J%tlcTVCcJWF8ZAuSy{;bJHFU5)6Ske{9h& z9T@nH#1G<8)i&!#Sy=-QZO8H0vHX~B;Vweu)#&7TeUh)?98e*{Ih(f9RM&d4cB$ax zJefiCu$(3M7Z4C*I&>{w31_O^f0v|e#_ zv{=NZ#L``Z`EGSVh;zvaS;kb~?1fr+e2Vzp+#IK_9Q}eRsd9G8&dG_&{+#BXRKx2o z8FbE2i~em}EZv)Tlc%x(Wr+P1UzSu+f%TFC;v4H`l^VTLWu2oz1WvN)ljs25ukAA877X-uUA-{B?0;*y&sb#ElYz&e@x;{;-d zX&ns`;Cx-t-%t64%r`DdP3L~;5dq^CJ1`&2Xl zJ(iaQD6m8HZd-^;4-1XfDyy~h3yFP^Jr~}~vN9r)lMceW(L99lQBw9B-eJ4T6~7kR z)ZbkU=7~O^ZZ;&{Zg}U6X>B`JKw8A5qZGHj8|jiUcbqIzHk7eFKfwib$kA>75_KvF zU6e*sSvw5@0?T6MaGQ2+oS`QThQ|C%URK~F2OG7FrQl`tV9MwSXaD9LtaT^#uy2|p zAI=ebTmVAIJa3h4b^UC)s|4kx{vdVWASG^}OWc_O7|ZkIWd`2wVcg?@#0f`Q$MeCMQGbu9BKuVt&9DG5rxQcZBKyuT+Bs@8M{pu)z6lx^{558+h#xv^-JvUJ0Oy%_4WC~UVnPki~BzS zi}ZQ~m#k!jk}5K{k;wB005`eP_zP4S33wT-JSf}}_-Z)+0#NJ{D=Yh95&$4Z@q#&l zH2T4adHBIC^X^eYyB>`)>D{+BSE`{F0VJhj>cZKMotS5gM=dQI^6ySXI%WG+&f|{I zsdvR+;<q=cHb$`H|-{hAYA6|>9)0_vQ^S&(s`m;vNrOMaZl$w2V1{onmyS|qG7TK zB>y8$kM*?1h}&4fl7D{k*Hg`M?R(rl_+mXDl> z@W`U=ZW5L8t(M6fxt)#4+PTYK=dVZ);(%27ZHlFoE;y7$N8#9~9)C9ntjs;~<};;8 z!`ATOGcSA5X`18(eUns3ofPCK;_DO=AK`l>gkRes9FVp@dq=_G@A?in6>-t>s;i`R zp?8jo%VicyjyY~8KoY(eKnqxSv3@doqNuRb+eehwp^W(e|$gzLD z%XKr)oz1SD&lIu|-#b&qxqV+Rim+0z+pcltrbZO%_e|KuClaB~|GI1Gj51Po{a>K! z$I07{Td;101W4!qFPE#`QitvL#rpg^Hk3luvlg=7rM>rCCk=Uo-Y7$gA$KVcB>QzD zY*Rk*#45Du(%(v_@M?*-8Qw}0kA1$~ivPV56<#lMDt(of$-aWrWR!CvPbd)8F!l}8 z>Ig>Ay2;9}6ta_BA2Srsk2#{g<9jWdc5)U7brtvl0~iIXM%&gu6Pn-uua)zw!_D#T z^~n`|77cE?l%+h~5VoP2?qOLp92P`}ENE?UvTch$q!1ZK70 zPG1v}+d(nNT#-Lx+p-WcFW*Pp9uBRJt|TuKb)hDIAowY>EG2(6m(x7QR)tPlQka>u z_{+YaAx1naQ6^t8E@kc2jfPhk=W@hCr|@U!%c122oeZsHYaOxxqP$lF0@=Fz?F%5u zSMbmB_-D1N8rmf2^zI7B@xLa@q%qHf_Q&j~7ZY3ky$0+2s$OE|$^a=?|9@?adcb1( zKV5xm6awBRrGN1R4*=G-`5@wGchUyP@z~<}`Rnd|kt>m&8aClA_f{nlaCJo~hG_)ehPQ2} z4)jT1)Q698P8H2~Fy06S@@&8%Sfg@)s+d9yj>{O^AyV7Eye_L#2_b9SYNgYV{*$U_ z><5kXivJN0_btkFO+R}MsRXZsA5qH>C+8vCyuiy54sc2&{-bV;QhG1CvVC5W0N1%T z23fLQ(-XciX2$O91%h+0tGi>tK7HVWJk6+EY~kSEogu551|*N(U+TVzFri}K5&Yfpz>9NrA^+@dkTSr=jf#<4jM3AoUK=yxXPo(?881_>dp9#0 zd?-&NUZz@B4?Q{)9wTbdFT!ws*_a!Yt!v9Z^d8JH1!$hVDE_Y@4!)FZXz zhc5~Iuk+3eFdScTX+K)FpguEl(2rVE)70{vT~rVWGlM>Htq8$$Y2blikPX#C>bKr( zMKr&uG~v+>n#{o8nb8t05-AS`cvo}|NbLFl*c(8dExyFX6f#YQ5QgVTQ$-B~%SiY6 zYATjj{TO9YZ?0Roid2yNY?m9i)Ee?2$B*6-N;|JymV`2cpnoA&gX0@QT}P@{*BJd; z(u`8yL4$U>v?VDFI>jTq`y=vf2>b5pAy9o@9ms1Dse4$U*n}ji?S`r({%FAcB;6DI zXth`^AeZwLsz?`&}xd*S49u*#y64LQzAhMaeJR3|v)}pfM(vma?C3_DONEF9j0PUV1w{!x&bWf{Bs5{gk!!-m>Qkx6@t~oNYHws_nmEl z?Za#q?r4VfGT{oLQh}It9hL~!N=Ht5nSqUTo1N_Jtih8fxlxb7dsjK=xv)(aSfmMe z%-Qf${fiF|;Ek#IH@=zJtDIqh=(e2p1{RqHF#H9w$cwqo7*4yIaa`<(EkDDxxsAOy z)3~gN#kHZripmTYIr=gyq6p_vXt0zO|NGz}0(9OacA5C3v1ESb-mVCKv}nEDd(=RE zWnxrdZS%WjwMVeMH2{nbD%wD~d{%&6A^^m^EH@+Jd%x!@+@<%WrtQ0{dc$GL1ucE( zQNk7TG2&u`F)ANh`hvGDB;LxAp_ezrfA6z9cu&rWgN`y?L2Z*P+qp`YB|f=lx_7gg z8d|We=Hk@igjN3WuGU>NNO+DX>s_k0;qutXFdP{I6#U{|$!&YG^du#}3<+_0 z`~ge)<*NmkceJHxr*Prpm=ND2fLR`TLkiJ7`SMf(nbD00chERcY{^Sydhej$M`zSZ ze)HF^^pNl%7lx|Ou5%@_OkC887B+i~>w>&{#qod1rkYE>b>47`wKbW`L@{K5Kh~n# zQ^RwhaY4vx!_)xd($Pa)v9#;DmiweE2?)c%a~+d5oT-|zaxBM`J6#ElPruz_DjW_T z>n4caMX09WJWq5KpN1}6mx@w6)LSQBQw2Updyvzg_l?rAT6WQOGrU)+0^d$RjK*RK zo)s#W>>A&=EuCs=^9_??;@e-BYitBt*_`g~dblM7h~E(82u2wDzDnYHz^Rnfce&S+ z$#4G5oi)~-UExOZ!G9B(EPxBbbii|;xfDys&>H?A#nWTt^ZMN|hsvofH*IAzR2chA zrvG3ri4w})OvoPPWY*llt%`dz3et*S8>MKE%bsB$VoU&XRRSc)Q9up{N}r398W5Vt z&#UNuG`)X^|KJk1ZN59W~H(I4?S6wsvy*0WEW2?S*~HAcA3SCW5(e8m4uf)q%6{1($Ojljzyv(w}x zYT0kr_{@Y>iG1W%BSw&#`GaVn2xEXddf_oh>=oZ|Q|hTz4DI(kM7JCKgpahIm(q<1 zuOl<Q#&>mFP?U{ZNJ4)8qM2xav0Q z8*TzT#cVMgO#Mkmp@)`(<{Qo96zXXTNTd}Gc3#3IVm)w^gKXb++^`q*7pUCnys+nv ztFMN|^SGP~J5y5XR?B^$;4qjwoc7_H-|HzT6FuFJYRR{MT4b^v3d_UuDS9A+ zA*VKoDmXoOf^2@ZVz}QW2Ng+nIsDLiB|R`W{YU0GkuDSAwTSE7^Uuv?ayG5!RpzJ-VkprtC0ziyKpp}5!U8A4@tbbgp9ts} z5dkgrBE?M<90n9F2gCluM@Gj$1-^HG(AjeXrKua?LgPgpu}2_%>8uXmz08hpXD}W( zK1N$OGy4&~j9`HiXCT6;veb)sj)vCsFshXzwHV3T|xpj{#i3P2E#o^YEpF8s^r4f=2NW#I15a^oYNbK^i3=$*c0+Ouke`@~%u{R>X;IlWx zUZuXig-yKy|5LTfU#a5LTu*TCaYhQirI_y&Dm}nent3(`ia-{_JM_<`xZIRZ<)8PM zzmJPWB@_Fc3GvOpbd-8-{{T4wf*ZV`cdH65QJ3b*V8PM(e2b|axPi5ATg!njcCyxV z@%ZrC@?jexu5jfF{z89&ex6a!CcoDqqKWT8$TW@sE!QIpY0oNx2;Qdx#yoG5Q`x%_ zhTBU$d?tP$^jJUCUhOCKg{|X?Yv6J)$mBkLeq@G4jQ;&AO+)|7C>H~yq(nX=VFrRU zG5Wd!Z~;x~2)BGL%IK3Vi??vP0S4F)8?K^1>ya-|v@5}9)5-`| zb#)kTmZZgP;9pi(lrBqt4O##>m@fVrhIR{$A9`f!wG*Cd`-!gailRR(T(!lN#)-Wq zWd_*OY$f-q8A9B665BZC;zHWc%o&JN9q=YTx}OdPY-~V9H2}`UZebbwZ;f~PuXAs{ zai?AS(K%g|L|xRq=5eeD7Qy<6wNo68Hy%SJM&kjJyA^_*Eyp}L0{Zc+Ch8Vfj;JQj zN}2xdez^#LfmrhZEIODWoo4D2_?!t8UcrU^XfZww&^^%e7wz#1uRL6W*3cmZHfLhx zOM$AfT@qb{`LoMQU97tcraA)Qo+tRw4tHN~)` zG3@&keVg>OU5-LVKOh7ddCp&1>zftT-uif*gLz_*g-YyTnQ%fFkD5mc2N%`}7J~x^ zD^EKJw}x+pc&LYkO{Q@tsX(*!XIm`^=WA?3v7BDlX%@{uNMW?bpRs*oWQYT|J0Aue z{l=`}eM}Q5E}lE?05hygTX$*Drf@~x$;`Q$b7?zPX)AphNI9>R>*FGrumEKlh(B5e z@K^9V#f$U@4pu2lZeF^Vd5FlKg4ITS#u9LSoKf@{o)wvA%#_25QP4pp46#~cfUs=G z_Lo`65x{QW$1wUBWF-7W96-d*{u>cPmEX0_jrf7&;R(KEk-7((SvJca9z(XZV=e%{ zXB4FUzfdoYB_qN^zT|4Xa?j&x1_`zz{*){NM%DXWT@L=bd z^5_ZOtyD9u$aUBeyo2AC2OPS?yuJiJ2A=6@8RE=1 zuv#?vu%?-+9uq*F1#bva3Kv8RAaBd<@tb#I#DvnR6xF^bA5YHIz1|Nun`6t>BQQv< zWicBN-rf!x7foEakx?n+lE571$+Dv@mBt>YL0O*HFv;2HTmjOnZG0|Y5xZPw_t(4X zX7Wwg;z`*sCKK2*;~Hq3yX7fm$@dYM3FuH8okZsGaQ&3@F0$#QyzD0)7vaY*DIfcp zI>N#2ql6llc#8UG;ONx0puW6OewZ*NiCAb`9hlm%GO14;njY4927z*KzJo|>p>9wY zeajZy#pQC(6dWOfRZZyy%#C^e=T4f-k~M>7Q)23`^jF_@CZ$={aT5}tuC@%%WZ{9K`Pj}c53G@q_228YgykDV$F0NA1I*=l&MUk0b`d(ZY4VRDe z)^<&Pz$j&w#y=GjJ^SK$UHopk@&_TZbVH;oVwy>(h-gQ!Mh*|Jo?(*>LC>4RE{~>n z>d#}`gL|vFFDa3J56UW(rT z5glz1$x=$lB-`=_5~G?+)s?wF*($j3mJFcs_lqckUo=!NcdFRwnoNS2 zllu!ltMe$oK?jQO{J;H>gJ-}`!_UzQP7slrW7YDEMnn%xxEu1&Wz!!NhZHYBj(qu_ zgA}cS@z-!9nS`F`&FfxAGwwI|py9}eQ!O(B^_8Yv24$s^8__*p)W1N0opHu~$?NzR zNV&;ss+9*g{cTWn@}|2JHPJHRc;TqHlz42a zB@`C^?W_5~QO%G=z2Kx=g)Z9F=cwSDe&1A^MhC7>)DNp*9{ArTeoDgrJQyFeX7{{h zeVjur)O|jDKP`(w7!$%CN`EZB{Xs9aAbJ)Q z?#3Us*+vD$B=-Lagt5QPOqe7|a&&UKGM{ z0{U#b8!1H%5T?UQs;de|Duk5ifbphE`mU)5b{_jR9<`ng|NOqSN1QU-QBpY>n%wCh zPZW{HAI2s}iHR)fsSuf(*3qxh#P}i^lp{DO^B2*G>S!l)9s+!PAd5w3NK?WBoir|CwY=a5c6&B` z6T)JxKvZkMmyxYAO8RqvIh_tNM5M2D_6vRB^*f=mcQoj+Dk(9IHq%E^0T{+9PMCpL z)leen_h@;RZA`SqCi_djBiVEfF`!~VhkAgXt(G!0;(RVl#8C0dzNhTd*{Mh%;2YY_Q6b zqq7*Qxm_1UND-==!e5!E;`F0Xf+u1i_UM)W=L{ha0MKWFsA!C4$o>U75d7X#_A*N< zUgBZgl2|gBeyQJ0xRykCIE!G*P%a#{{XHWm+P2&?8HaCwV;Qmt*YRDEjaXa*tL~Py z_hZke0?ALSo@JB|tfm3JBY%OWVi(7@JjO~nSB!Oo+_ttgjJjg$Dl&hGCb8pgYgMy% zVg)xXm(Z5`)@A~Eb`C7}Eg@yo}HkXGqSOm8~v{T~Pppb{D}8L2hBOVQdM_zTLsXF<D+UKQp&4RjS_<1V)apHkMR#i*W_&|j1( zdxy}bSr{xDt8q3!)sl+f+`-hz_nyyTYvmV9+ zdMYTgfmfY8g6W%2HuU+T>Oi$kl7}9Yur`%9eX`loFmqxB)RtR!+*_;@rT$uDGi9Es zppz_p^<5Tq0GpOb)lX4Ej)dJt&_Av4k8Wi)L+nd61|HoeoD@YU?^?--OuYYo70Y>F zjGqbO^lHAXnRSxqFPRm}V=%>7JCz6OS0-vXmH^{&X+4SZtt$cA7f(S0%-6{z_gcr2-Bz#;$b6bzfz~pDs*())%i~7ac3QG@GA9 zuYnvlsQBBd1QITHghri!7f4){#ndS!32W)l@D(GeU^1~tS?@JpU$sM4#?e9rRkIVu zmZG)EFV327mdMzOgs5}xA8>nFH0PK5EoJ(8C3?1bVxF5b!3 zY}BAsx=_bCk$w=xh^BGQtG_^>1pW`!-a0C-?oAggT!I7*?ruSXOI0Aay9alNpa~Qb zG`I&VToT+hKnSh@fO>Y7{*sX{?0oFpEUzdiK1*H~0L#4mPUsaByYN`bj#e zHKqvPM>41FGK!dj7RvcQHp;spKP>>jPY8vKiyK;T^;bFqxe1J{)ouzH{6HUohC4h>=SEh z;{IjjMAGZz1VSn-d>be4dCWa^3O*{L4m>Db`3u6`?mLWepjgeL<*v@m?G5v{3I$Vu z{_(&61{Krf1h`GV^cA=Gc2Dpw8-uo%pAHk{MgD>^qVS*UEuQR=hddWCFv4cv>pCe~ zJBb*^8{{)>E#-Y;bA3zQ+WXiutI_LAQR$bn6)*Hm2J&M{x+?S#F=1|%L(h&iaCpIMJ7?NaAt(a_E+KZ)a=(3Vi&sToA7GabzIde}uUI?PG zaF_OMYoUUKszsw@wWG1T+}v4!3fULmtOTTbqa$M5n(ar1!#5q`x>~~w*P*am24Igv z+Q(z<@Essm3b-JFF(6GBmgA=;L^v8p@va`hYQ@E}6Gj4@UGH$E7I~BL%0o5cja{qx z;p^1(uwynP(xpS8z>Me5Cya5*VsmEKOdkExaUR2zFeNeJ2P*+nsA?^I<+ka|Xw6ry zjrDz=fAYDJY!ao=d8~4`Bv#T zdl5D3r2I}}__{QSY+UHJAmXj#9!DmspmI@wu(>-+`rK~PD5E>|!7)On8$%L-oFqdk~6qzM6kPulRd zmhH|I*h4Fl7J;LIq>f#~Up!8iBf6){nD)YSv!;FHP|OBQY2DpeA8d;iTtn_pPZr)w z%Ol1igr{!W_cLMtq+e+I3!|QUyCpnqLhrt~j^^&5_16LE#*}zqF_8CY+k1;v`1Iu+ zGPFc}xAoMqF>w{f9MWVf?OC!YFL@cJ-28~}TY|33K+lPhtR_rqTg@=Y{=BU%`+uEt^fl;thv@|^pVa;Tvr`3FQMkqpU_a4C$~ZQUG+}U-+})7%J;!3 z-f`U+7b($F4=yauw$)@54K(8Lm}1Q(vgf#+!-*KvRnMNiqmt~IWOdFYv0pK^lKNl( z%-K4&o2%_6Z-V04kYnfE*AX{I2!uZ4rZR2gq6s8f#SmoCR?pe!PcQm(1-)IU%r1_r zcEi9xB036z9YJVR$!Dt+2}IroY)x0ix&5#zxq{vP^7dL7ObI8+@Nj$~Vgwom{H!8> zD2a9g>{sN!pd)?Q(JhhbQH%BppMz>gmFY0xRun z2=RVl42bh<-T#Z&40)gmpw~gy&88cil=T2=I{44a1H;B2ByAfG`JXgDyYd80)En1h z37_-< zOI0t!Ficc0mJ^{J%Bkc{#ZuZ%z_!LsZ4&`=DClGRRb6O!s%`m$zaPBB1byf_!q@s) zHZ!Z-X4~x6!B2xf*RUp^wz%!%Yn43asVY91J;ZxovqO}d9l!FhS?GGUy710w^u=T) z%xq@noX7s=&$!RqjSVcqGc2YMiM~b8z=ub@9OgV+h-p{s(3wGrUPr5=k;UyHr4Cil)7rWUou1D(?o*QRHq zpGKWT$2;pAzD7-~SYPI)Wh=La#O4IrKcjqT{G(n{QmL1u0QVvFw3tr zA=9;*vc#bOlgIhLqY_R~xnCPCS?pB#>}1h}Df9{$^r`FXw{*8mdwIMV50QUC{?MdS z4P2A`>n>aIisDo;KKocsLP8y6e_JM;ymh>fD0!lLga3M?_P<``6V|<#P2xUNovr5> zL?&fZ7|XFTr@qV!{Q721o~ESSq~r%b^LRxvn3wap8t+G%t)%!nl8K*?O1IG){CXj& z;q7~mdvTB5vn`*~yT?_(gP3%u4tmL-3eLPO4pioHAIUBj8RuJo#OmFBz-+`y`@JH! z&GV}EMqlTodkC`CAVz%ATHStONH{b7fJwyZ)&Amncb!Y`wKEn@?sdqQ zv@c8Fu`E;jr~9K#TU~4BA^);y()zpT*Qo5h+mE~TRdBisGe@CabE}Xgww-k`?=M zEjCEcmK_d3e@B{Msv7(>9b+;A4~sbpGTA5hG>&5g!_> zOD2B}e?4yDmo=a}LnsZpSP7YM#{?!W?4yyCwFbc>?+m#%>hF6OyE&#=JlTyY5-ZP5 z2v+oAO9L(+l*}J+tSrr&+D(7l_mnc!Kj^J7`I9@j1Q&K-4QvHZKFr6MPD~l}I>iRp8&_B) zwJB=CM!LWo#g~d3mqa8#RER?sZY%Q2C%)B*d&tsZh>mkxdSEHBl^3^#Qr$N&z@+{2 zvB=injmsGhU48L#O4q=%p6q`8FlRdXiF-DQB7$)yi?joI-bLj%)q*^ikS`93TgC`9 z=o!j`9#0Bu8Yj90K|C4_%ehVl?`!9u1e6mnDafGc!Tm46&z5Um!J>lI-^OpnEBf0% z)XUv>3@YRxWbS7u?t3XUL1%4kPn_7|kG=ye!(Wl#cm(%d)(Fmh&MG02R=%AenZmaj z7j%s&r(8&Q9ip2C*qeiuQrW1Tg!KYPbv7lG@{s4>R80;EWgGJ+7* z1Fh{vC3ehlPH(R}Z5>`wE>(6{NEuQhWH)Wl;s-j_rIMAI(whoNS^DQ&GwvNAehAW_?4nk7lI$WHPm52|}41P^qEg-CubP|`I|F!GHZbgn?DUCz^ zkR$Uh&T(+JG3ByK`3|-H-BH|v*1|O-?7-mmE%H=hUts$#S8O;A8SHy|xg>??5w|ku zIr?yW&*ql`j zjaB?&YRJ;`hchEX5wI)a)FtpQ-JD_(NKZ^SP{BVMM(^!jgDV$(gDLvo}E@3Y^7+g!5Kj}Vx%SeAKBs` zs608WYD^BKm|JGHqM0Htcj^9kX`eXvrE_-DzJqB9e0-Spd#a zOv?w7ws?TfZi6wFF=}=?IDc6|A0hHQDv>83ulPw_`z<5&S^U)}gHxMNTFNThD3|Xq z#1P*5Z;8)+Z=Sv|j#5lceG`MJ1pLB0+(~1Qp6J1@5g+?QZ-Dhsi(W>+@ZqWqSP@fgo#03@dh{EjR``8}Z9o3q6eA$7`nR<4K0vyq`f9SCJ}HGoOuKU|mY<#`Tvk8% zSq4FEI?jOdJBf1zn0+#{-x4|wzbHd67jjrJAO0Pv*nqn@<)wqG*DwpcCX)Xe8~(Hj zR4GYyq=lCSpPUc?YmlGWyV$hIzZds3uw&rm&~~s^hx`AK3L_y#wx?GxTK&XvrAPG` z?`S#$GA&2E*QO#;EEy+4DeMNCKu_6-LPLvEhgk1VIw9*Cx zI;HqS`Sb&<5~b=VN~K)s(%IY@U6qwuK;W z?Iio*b1bPR^CT;_^+|g|n7@LiO$5<+IUfUx4Xgp5AL6&B*{AV*Hn(sY^CZ*|nOtQA zuA`cRe?DfO@<+712@UX?_LGCu)ZOmHKJCL^miI<~wr7y7=EH3NvIJi~X3!LH854|Q zk5>*20>d}{Xq`V8ljSA?bb|qxru*qL=cg?Q$@pdszl<3EP0_1oM^)9?mR_;8drH3}25E~Yq!tX#tn)$104A=e5# zP;nsjm}t??%)M~zqI&?`lC5vRkWz;JwvA|Lvg2-+Wv!lP2xcky5@!d>6X{!t8!=|k zUZ&kr7t*vs-rc7)6L^JWS(LiFxd>i^4gtbM>9J7EZ>?~5hYKSt8e!u$-6@hG%^{H^ zz^n-vmVmhBqJ$_4vCN`$IvnS)Nf`{?I#-{ghmayMcD?4~_I4GfO%;GDnepr)g6P0H z;4Rhn?^F1PQhF1!6>MH1S-nr#1n0iY{D%>w+kfn6&{an*#=DycwZDy6cwz=`Kwd}y z@=TYck-G>3(vw5}aD6KLdGHb02tJ7g`$TFrBBQb=`-Ck3ZnJr7FU`cS1l&!agM9s(!i7wmaXNY%F7X`sJ((9Pa^BILUos_cj(9oxP~`NO0y%e_+=Z`w_^09BfV zY1CtT@yAQzg8bb+C5sqZKt?)hA)+->v&76-U)p*Y$shEgn|p*#>=c*bD^MDzh`9oL zL5CuX2uk(ceBhpf3S@~jkW5Yg2rSVd_ z!WcFXaG-QGCa3|4T)(dLTkTrp9SCQo6v-vB_Byq32poBvx>^?J6iCM23$1U*%e#ic zoHn22rsp`l<5$y}F-vCmP|9Qs+w;n#s^0PNAfsbHMUpn1iUS?C^h;l`x&OO;?oH8z_6733z~2=fGczNNdy$Ld!yte5+ir3U%~>kV-#PV z_N!f1IB+u0cL3Bi0raM8YIZAJ!H)hq`sg*fAMK}_>3hxUH38#oyxE^|TRrg362Tgh zhuiIA7jH%wLdcT{igm?fs(D4FzK1R~kgDRHpw&?tx>Ct~j4%VnRwu?T`*8lM;yd%W zEzgRs&ob0SBHLCzP;8fhCcyz=<7NEc{wE(<-&|`of7TZZG zPMQU=k(MZDi#pe2&AFpgfI`kDF9g5(7Dl#z=KkoxFv%Z!L4^jv6ASPiw|goa?oC!U ze6tGmX49d`Az_{AQhC@JZH(2T>QEXCo0IK5JLyNNkZg`Rv{93rqE>FaaDdOV9v>Bp9U(M_C(&e!e7RKj`d)_vzLq?uY zGE`m|gZ^KM3IDsVCH{K>Pu{zKe^1sL;=Rp6iJ`D7<{=r%p(K85Ke8?0GS%26MVTHm z2j);%7vR%QJDPg1Yx#yQIK>ZH zY%5;w^Y?LKmNv5Cq>P0p%+iP@7)_~4{W#3fNc>8j!|I;cdTHWru$3sV@E%Z9tfYsU zvFpE!vRaepz&Ck+QvuV>Q>2ko7#+q)JPAvu^7KFI*$t*Hca3h)lhX?I z{8aq5A{+9VDT(5Aifo$zkaXa9h0H8pmz(M5Zm{osr%uz{!S-#h=EWB|26H$aHVn=1 zDO?Knv^t~o;rtOj7)L74$g-aE@K0b;Lycg?Tx8p-+q&1~Xz?gl_9Cup&nHx~6Tvv6 zSq;!t`XBDi|CBU>`Vi~FTr(ojRPSN%Yg$vmRxrKdeHj*73tg@$1+)%8(fRwlu|L7`12; zHR))chPAe3h|93U8UTI4u`MXu`7|GS)Q>_;jJ_eUMbfmEzxBLih_-wNSMFd!=t>QH z+dAQroC_3mo-^+Zix+cg4A!n=zU?(B7CQpX87s1^}CvYJ@Q*&VS z+|TiS>Qb{y?JZ}cUP(e&k#tFMC>1g!PMCHQXo$+>Msj@N^osAgINQ)QsNo@g-dhmG zunle8OBgA8=^>WN+e_?P+1a45I9UEY<_x+)TTgnHAY_P5UGh8FqZb5?^Z4W(x;4(o zqllWtc!r(xR5Ho`{!^5VjiG^y$dI5dwJSmjt#9i{_u8QUTaEW~39d@8QMj0X&ad3q z@l3cTl=l4eA!e%OyksQs?(#~c+Tg0JnorxBBKL=sQ1k$ET;#Un)mxsr6qJzb&CWCX zewMX}3?_M>fYgBN*pETi=+LFFNxzqcS3f%q)xO5?IM6Ddd2^^I0|s0Q;W3^Bo_>cXkGa=HqNsz7KID(kPQT^%sn0c9rq?7cmZi z*Y*#pFr^I(nKp7(;yIt;;eN0i38i7EUL2vM%uUE6#8x6%zOC}Y!$?mx+u~UDoyA%+Uu7c~RbFZ0H3{)NZ!e;* zhqdsU^-n1lYYq_=8iY=D}uk z9B@yZ-%+2b@_Lx^+lXU`v%0VzAt6JNv`04FYyXyay5`cnlUgYKf~QXsuv{K@?L})f zJ;ElHaJ9%ovotgsFF#b498F9I6lG*<$3?7CnSwvp*?QKoK|7s+DI3>PDK!^@yI-ff zUJiKngCqCeh%X80Gs~moc*C8>di#OgEVbLsBH};x$g%^nMsp!T?#Z4$Ne{ZRUyUkO z%cKL5XiHdYsrr-pkL920-i~h!+Xjjhdz?x+x%!A`A_O<5s7&Z5&-I(`w84u!#XtdK z3(m!~)sJ_a0a0AY6~D6QiwUBPGwo`S<9?vLPc{%uqgprb~C4mC|(xbklF ztE(_6ixg0N{`v1F#R92OREdioo%ZqYwIcVr<@R#zVaZk!5-Fmus2MH#h(__u{5VKp zM^3zH{MK8$EnF@?s~^(DI zhC3V)l8~iu_#LkUO-~h`i(U>)YqZ3Wq_s2_8(CbO5eWG`8?rk6vy4aC9!n7G&K_;J z`0!PG1_Ct(TEc5G_}l%VqAakK=Om&06=*eKcbKf5t^l-4=amFA3rHL|d-h|VFR`yC zRSs3l?0gU7$;)g9g4_CnMcI&aTJNGSLPMWX zWDx48n`i0nT&+*@1zb?ku3aCf3X-`A-=A8+uf#;PMZA%D*#S_u zefsJ(?KcU>)K>W!_|0mUN22w7a<0sh@@$YYP=msCNFAU$J~a@73Z?)nQW+&`{B!(? zM0xbrk6g63$691nANBx~$*}y%AEP=4_D z62J^bwNVaeV%WFg#uAcwf;qH72+E4VS$0G!60a@buKGFlQ@UiJiVLE1*pHl5bYjLb#p_o;!m1t^KV@mM{PLKhck(uv={StC$43enhY+XU`q zdr$*hl9fH!X$8|pV5)6pl!>1{GkgZG$v}v>n;KAP&zkcFY$Xtq9GLkLI^5rOcz66V zbJn-Iq&SD3C4BBC5q!IJ$hN-BNa8Z4zya;FN1k8QmUwGg1INO@BraU0y?FAztF!~~ z_0nfweGV9AzRkG6?(Sk~ee#h`n9>VShoUz}iow(y_U!|9FxAC(}F>9c>#f`Ak-6|b?k zng(rZ5(bp|fW59sYw+3F};3r;N3 z8oI}!hq?z*PA7rrwKaM$8Eg2r<8t)|?Un+tU(mZy5x$n=TC15+;?T93nuU|gzaW!- zkg%Wdw5OB~%4LNo?rU${4hiO}Lavh*asPhsv5((iBIG715->KhACx?#tuyi_7?Mf> z-%URygFLH50GI$+Ys5f2SS)1ST>$5H??I=DcyMh7uSu0gn`i%??pjN^-&Z}3gpEeKu)nBhD^VmjwxhBWzhJw;P*q1R>mh$Wk3&1n4FA`rVh)|F{~X`gUI(2F3pdKALk#0c}F6NpDGB zXry<7ES>6xmGP|@>Q8({Z$>;)duNRPTu>+7~qJc#Cro5 z02+)VlNZyOd3p`@P--+){xnX>mXEc(0NWXIFQR7Otna8}w8)s^ZfALa%k>+slI(kh z_la^9W0(;oL?wN70=ubEl7n0QH`fjYw-(NH3o2>d1 zW=va!{mj83^Gbs;uxZ7|I8yz2vXOP%)%Tr{d5usJ**~&=`|cz%1Zf0v*H%M>)HZ`jzUxJL_jGtviotd&x@EUP48e)CNj2i209 zX;0F|sTK~U-Kv)S>0HhHxm~Zh9e)q4#$VeUD3`h$BU~l|C z@}NKtdJ(V^p@L`aL(jh=4Z)A3ni`k0kKVHzEus4T`XnIiDk&h1(HtJp^wWiMBu~#D zLpx<~N8_ynUts2{!RYQAQO=wsQ=V|EvO^zyUkUd~iQimBZYwu5k>8xqMNVHWKV}|V zywBDXkz)is?sa?QT^&o?;_781z%I~r=txy-UoB@#%3z7kzkX9Z_1_9hz6Rj|#^`#V zfbfC8psNpQEBbM8v2(6DTD+@l1>zlvy&y&z97xm3&M`4%UG_gMtMq?cL-!p8f z6*tQlCQ~=iv8YLCI#qj2&r#7){q^4dOMLf(yvgI zCF#8rgK@!>fb-~{pP)Tm()}p82J>>->u2{H#!N_7*v5&+VC*t#{d1dM;q6O(Tx@5Z z!83++Lr#L*=-S|H(Ag*%0wTE50BbpvF0m_rwzskO9CRybmv=-W+`G+SPssH21g}!* z_A5tr%CEY)8gr&5?1JUo4zhNyoU)hSugZN_UL5&OX^t0A6pQ#=9j4zDzhvyx2;x^M zZmFwKmbUmJ#tFqXeT&4{@9U1au^ag5Nu=tN8OAI2jO3+NdEIDV+R2#xsuBVFpS+?h z%-|AL@=KE0ch;zZoI*=>TwhcrM@ZMGW{NDStpSL&d4V?ZD>s#1HR|(0LgE$d8h3eU zspATy@l&n4yyjKeu=%v}et|DuAm-q8@v^n(@aa$?*Hr1IB5GKQN()&cJM9nseU9s< zEG7dkV^&GNaYF?wl{8t5dE#jP=`}44hGulHd)Rq3^65*43;XUidfKXh0+Xj*!Cfh? zbZT*<6#u25I5R3#fyTlwMSI zU@x%h%!@?Qrg_ZiW%DRaTL*i@xT9jrQq4vt8Dh%z5`Rk#_K*wE;8Ot1W}t-U2MX|n z?>Sv^f#t|+#R&b_s-eM$%t4H&tOGb$wB_7pO#XD`O||H$h(wU?pkIXg%YMFEu#ZTG zRg+tGLW5Jg>YCj2F3S+&5A9q;qqM2If_kPkmChHx&3u{ou&{9@JpX>nQKr>kTuBov zmLjU^_gbNt#i;qaiKPMx_{42YmcbN|XL15pW#%;ajv9Q^nYgHX#QEmab)d%?OvWw{ zm|W6fW!7FkAn{!>%KIt5S44_S!7oIM8B5v7%3iVrlctbOc2OTtHi3Wu>i%MGeis1= zdr|s;tjZrCFFj`y|IEoIC&eX&n3!|!;^#eH#1Ov2!DJ{!=Jxfg84cCByb}~h$f8Ru_2lm42@-3vuj6%;a91rj0btJ za1bO#l_A8%aYr5An6j<;q^iVSkH5ssp8^M2$f_xd4i}5$_A4`uK1P}N+R>B+}|U2opJ(EP z8NW#DJ<{+?q6Cxq`a2V4=G3TU%o)1$0d=)sTc#{1G9E4nA)-uHDvu@f`il5UMLVdKb#TExX-1x3plimXJ*d2|8$)q+hA(E1R$SpSnZa zak(7x3@zCAyF>^5eh9rCC?N2s>GIy_TlKYS){WfGBtOIA1k_1!LgT_Ml=B1Ak98rK zwhrWJ?Ga00jw^K-hmrUz(UqXbTcAw*l{gNhh$pWx4=M6I=i?4uzX&RXZO59Mnk1CV z0G;g~A8N80n>55v5RSX<7j)@*dD^9&u^2;xfnpphxPuW^=D@(YFdZE&Yc=4&0O%}$ z6!w(Zi|D)Z@=!JWaW5>Ip9D`1CJHfR!&t*hA{OHyDf3V!Hx7vm>>$l?M)_yK6l(%4 zB3pA=S`PF}1E9m+6g-bB35`)7bm?WjtIGtSvVlAU>{#z_USF}ms7S|pKZFbqYHOl+ z=L9AtJl0nr3Sq?cSj5?e?f^+0u*ZSmhFiYlvRv}z-!QmBjnQpt(Z!Zn2lf0Y{Y>5( zFVH@%eaSbnzQ+VJnfbWa)zt&cQF6gd&w*xxBoD?@P z)*u_sUefm#3*u5rqH-en`W5J=MVqtTL@E4_0*Jzl{=9z+!53rE@lj~b9lx8na2HUQ zjOqX)7p9m^k)_vu9Xi%wBoe(6No-D;pSVJL7v!zZ&J-o;vdRA(dbX}V&W0LH%9~9D zqbnx{>4ikj#vrdkJ@Fs!px<-b)TQya)X0EtI3QU2m@UyN5W6)F-cTDuSf#k-Y*A9t ztlbqfXBUMH#mP!&pa`o2wgO%VC&VjqTkSAAkNcN*vtf)~^6v}`>o8#a05p{l15zBT zaq92Pk0z*VNk+l>c~g8w((};sdqexo+|TNM`o13O2e@vStoDdn9!eSs(T-`}9I4&% z;eWNP@}K_aZ;MQcCOs(bR+fPivLL`#`AFAKmCA9Hpj|x%W57V)zFjJyMc$l zs&(rkcDa5H!K5a0KMab<_Jq{70nLL^ez2I-q@(8YvCks5+J^#_P)=#D@d_s_tJz`@KAVLZwLWwT1!`-)C2D=^SBLdleXGl?><-Xiw10& zo*_FRJr0Dt${mMTwbA;#w|ywWKT@Ed6}dl-4_wedOWavNMtX>e;E!Y48;uK23`wO9 zMzobm->UfnmbQ2zX(50wze>FLLRg3!5%O^#5zd9z0faQ7cN#dEvyj&chVFCc1P6^e zbZgMbBsjC#c`^T6Hs(qulvxGX76fffsBTFjbdI|xSmacV18DN&q17i82vQCBbCXdj zrbfyQV$ktUN;~ZC<++?f&-$R@AohkP&c=a-iJ<%Sspj-`=%@v-9aCjp$^ai$W6Y5P zR93UbeALuz#FOxy269s+x$HmSjZ5+{H_W02b|)72($AFFa^dOfNa=dpbu<;feB-?{Bnodxf*%~NDL|TMZ2P) zK0QBBNsml#<0+6%8gbn{k?OA*Y_|T7&?mZSK*s^ zL5P0@A+n66nnBC$mK8=pteL?b$xaC7-8;L~6nat#9%4ZC=;~Krnz#5@lw;jeP*z@& z@Gpg%|90(k_7UfM;O28qe?|Y&HPt%jc_i)K35cnSGwQtm$jC3~{?|?VYl_EH5yp#g zAEIR?;w`Ndnm_CaUBESj;MC+m&;3)4C=V+aMp|uL5!EH&qUHPDiTa`VR#uHJ45^De z9-Qtp`HeLPt}q8UX+ZazYAo)|%EoEJJiMur%5tTqsTGGbmjUaDc(|HYH^FtH0_&K} z;FFgTXd7s9|8M9i{_oYSn5cDxY%;60wX#x^(13M2UWUNvP08iik(fFgJZk& z*mP8EGNt)r3r->yg2U2BZI6C$e4FgU{6+M{_@HZ`heDDfiw~oa*a>+RjJOZgD3;sJ z<;FXC)nu^270qGgCa?r2WJ;OW`WoR9pnT%Z_ zigAu|NluKn!|{L62ZBHE-wh$&8PQ}oNDSkYC#y0^>pEa9#$FKP731tlK6(t{F6>rp z{d;eJUip8)+>_9kT-I#5uqoZ2bh|*xkdG@~le}Jp>D`u8n&d#Lk*|5Q4aKn*>xb$K zF?RAHkqM{~@~$dL!Bc|Ajw`>+F0lhC_r0y|gu+QYevpSUPn?9NK(s|t8o|;lt5!}c z46<8dyj^dSqH_C|Eazvh)?K)3*J&up2kGnzwylA*-~T#V{-=$4^fY@1qu{#FAH&}9 zyZ6nkHS8A)Rljqxaz7r0pjMy~ zVr~lHA04Ub4CIz ziMe&9X#Ff*(5ncA^k zQ(&wuOr`Yh^paC;0z@*q)s9mcNfd9I6>1`1I&o#u>8TrWKi@ z8AQ%Pd7%Xr+(CXNCfjzvo&n~p(;hp%$#f&2{buH5d*NK7nBBReLDa?hP&EXI=i_Jg0y= za=2t(B|yiD?;ff9V3OcgxoGxsl>=SgvJ5=e5>~XJjD5w=U(@O;e_7gMKP{$MG%Z0o zTJGn#q@_R)v^;@zYk#9Lf=;N~oiF9UUX@ zS5-h08w{eE)tc7%{7GTF(Rw;2!s)A@NV+b@Oa(CW8;;_q;&FaFpU6z`aB^QK;51LT z2_Apvo5xfaoQA}~gv(`l-#dT@4}lyb0=-%jL)>fp$4CBMN;3_$gIt~eM)Tm42eFDR{|LR>1E zYF}-C(HhlxWp7|di@pWGm5jHk6g9WH_s=zz}t<1#BGMud1HuC3HO zykw7>?Rgnvmg`n~ge%&so1T2EXSNx1VOgJi@NgwU5(3Q0?j1(<3Q8kD@23e>K?-;d zZNo?X!ajKHNPE=f$SN@!JruE5WiLfuf#B12G3>%14+T_nzHz2EMb_@`wHvbd@?>B2 z7IwB|Xnm->Lz#)4Uj8jvE~WCkLQ>(a`j#RGK5v$-Bw7I0s>!C~M1RWH2{j`@aNNtA zG1z54RIIG`OhJQYvs|{J3bq-HK+jLnbI6RuO9J{Q0>f}s$Udl)%Ms8pXJn=FJLu~r zF24$LRteq{WwK(Lhfz};;9%TkqxP;~6+)&;S@)pjMpJHWUPwF?}9I zQhSYIS)fN6*}1N7Bq-WXA4*w5N5DG0Z+*+zC6~ZGKsOh8t>F z?8POn@3#|$oE&`_2LAH5ash0WW<(1s{U!G`&$t{9m6Lgq#@%Pq6gL^aIu4eo zYL}+?80Dlw1EFgqOCJdRD38KTmFX4kx-sIa!;iFfRR7h9UU#C4KfUS(e9>R2& zR=30{ICGUM3;|O0&k17sg#rII469PfWBtXr;R-u{<%O2;Ci$I%OYwbZxc81a>iW$1 znB)q6mHV?T7hMs4Wcl(6jCgONd0X%b?S?$B!D;_$H(>Dgc$jP)g~R^14;Ue_KYnk` zgnN0vSZj&CJS>89Xl@NtSu{RcO3uZb*DXa8wBdB;ig*oGvwv`U2CbZ-1HX<*yc<+Q z!ZsX5 zL!`&S%Sz2k2Pvn~r!ON0AkW}Elmji6mXZc@$1m!SnpO{*@6ZQfthaGOyAEgtqI=`9 zp5mmSUr12L<2M1ht-$yVKr}HPRZQvqad*(t4)i3+Z6^!F950eCu)9KiN^}+v6g!H{?GoHCa(MyVGAtC& zkusW8!P0{2H&aidg}KL7zxYY>_Qj6+qmn*gy_+%o!NX5}jvn!f%oah}4>kZoP02f& z&AKFH4tumdElbPs|{fw#}JZeU&uC6vh^=Fx)$g@u0=7 z9q1d%Zx}$cEUSbDqBE|9f5&;xR}j135$mxu-s~V#!PX=Z7o#(Qtv9%+&CC0|G zOF`pg=3>>dAkrAL`jdS{@aKyAFGp6EFi&K_8kYFn#qG!)d{UQ>6%ptto^!8Rb6cVT z1tM|YOby;75srIyvm8fz{iZ%Rag2|t@|DtU;r!4>3)ohqEX=gDA^?9Qur1^1ZxyNX zvIh-%z=d}A?6wFn!(ee3VYf}e7EAVs`O$Rl^Z5&^vQzUVO6bqlr3IS71D#IyGum)L z%@NWi+?PWgAr~1jU$wh|cgj2kx$n3MzWuQcr3%datniBsPcW)h3$GWY1Pn_To z2rdDFhv4o6clY4#Oxz_vAh-sCySqzpcXtWy?lRZyb?#n!uT!;8-FxcZ@2mR0Kd3n= zx|^1_yWjDQXZ!}j4BKm(^ivy}zuuzES1*h1sFW{o;7j+Oo^p3vszz(A05XOMMIs^- zqG#pccK$C=4+O=2d8pEYj90u`63%HE zy2~vz_I2rnWas!0RiBFY(=r`>3orEW^Om0s-mX|N$zdK`W&zh=U2Ws#mHPD=n5WF# zIg(ZtE-v5(q(M3IpsOp+1%S6*s+*bC^ZT+;)J)@ua#1dvc+|2{rvPG0KHxi{jawRF z!A^2<;TIK0%s<)sRN6V&Fh757J61O(+X@|*7PN73tlnQt?X0~u({-`3f!xYFRIXpF z>5t@_3uI|BHLH8RTiO|-UbCSgLmk&ePnu;?dZ91&R4@Jkvf_NX)*p{P)d2h~){np$ zcnFf6{W&71Zecc#!up#~Ann51`UH?N1yvvkP7+nGkplfAR`R=GjP8arbnR-KlNp~u z+yhh4g5aG5FwX_*c91=o8n(q8{JU$D0Co2~YmMGJuwj8zQEATZo z6(4FM`ib*k_ZdA(mGqOEvE(|D>uk%`xG6GJsTvriP06XA`I^w5 zW5;Wv*M?dFe$>iye=Un;`EZBrS3f_x|4Kp>wQ17yY zSE$;VBqwbYt`8r&hNFZ=9AhCIQ47YNz~jP)Yn>ZA@$~o2iQnZn0)}5F96;`FwSPRv zeZ8XR-X|JlE zYv53y(_3D#1G7F+cT@7m(8Npa|207Yrx`ump1i)X(c+`2CdZ@MXUYg?K9U@O*TA4R zd&_-mo$cs=!KCO<)(P@^8q=MrCv^Y#j#jgjmcKT`nxNjfoQ`mmZvje}Pn;*ScaqxZ z{;odr}?Gv-|0>n z!;c5Km03{5BwfWr@A`%sblfo8MEHMdVzD+=*>!kPrMMN#ctDFx^$}V01@@z{_~vaN zFwrIIe3xxY-I$0X>KCTi162WiJ%(OrP>~Xp#9;nEikNJyXM}YejALAof)_>EKYmop zEth}PB5RCeU|iHfn_Wi4+vlH9QO#*ga!Jh9`;##l5Il(gDkdhRIZ4pF_3@W3Z#SDY z<0wn1Ihk>Ulb2&^(zO;#VA2$WVQwUWNC)>a0#p4T9Mw|EQUQ$3Py@;vAg3|F+k6|9aKdOjW>xo3LBgyQ@EDRd zbX*ATO6Df~r%oQ~QGb^s{(~_pkoF)&CWy+GaC5x?1by5UdE6>wFnb!X=-0Ou^qV92 zFX+}tRq!0H`!l0fH^DQx*Z3)63`{}=bD15o$Ck>~Uac@LfCmQ$1+N6O$XffS#Spa zm{D`v86R4Bz7z~s>B{u zD{bCBmhWYr* z$Lu5U!7sXI3msC+hQlLa(pS&r=J|8G=yNJEPqW$t%JmQ&T6vWzl2FIerInzRAX2ft z>Q8)z1SUG-dHbbAkf0aquNe;^sti{^gVy;hub?VUh5_Q z$0uiBpt@RrE18c~pws>Wxig zt~llruC_3Nz1e4lbLP$x+ycT%`jNNN2fqWt9JuanP<&V=8!n~Q%GFYE>6@Q+NIdvv z7<=cf;kp|*q_abHi@Afpf1_(wseN$^2?{96bAOst)Zcj zJ+${Y$IHIiB-w`cZurB)0lz|OQ-9?T$RUGV@_!587vdn~gU||U8K7We&cPimX_?dhY|+~Ck7Hn50S76=~TEmX!SKMyw&1tBzRI(>pg zG_nxOpAERsRpoVf$t4l5bT>TO^bY>M*cNaHZNeT-!r`mp==Ux2`E50lf?lkRMF=oA zWyfAZ`9epiIuVJnq1oj{AE?eu)#~clFvuf5DU|cltMyz;HD#n}sFi`=#^g2?ywklM zW5qufDgd1}UCOBm)NQ%vsR$t*U!~2P^z4<>nmjscU7^W=gy3ms37Cc8`HQ+v=)|HU zs+ai>J8v-~&`zx5F(dMYy(Yd4$f10co>{KZ%or{-ZHeY4UJSXW0&1d5mOBJyWn2TRa4^LC?3vs1Q zi<1!5-D@m9Qnut|`f!Yh(oY`Ye<4gd+?W74*q?7sSF1I2%JNysekq;plDjV40jm|_ zv*X)>@ab+p@!?7LF|E=eL|o+n~zS&IW}q{zygPQoc)HZhy4Q z^{tFJdQm8FlR-Q1s=3AKgsf4R+z|)6I5kXUG-pvz0C}}w>Ztm}ngn{ZuhH3sgGBw` zKkr_!a$aoeo@dKa( zaBG6e_upHhQ@Y}4>g%GPk(Nx|ElsE?Jnu!R}9itZ`~a$?279Wc_PZq(`mbwvAz>)E(5=C3Nzy{g|mY@>e&_$Fut z52=kK4&`aYn4^d>=>pk74W~V|o=0rZ9VOq)Z`njh_FNVc4gndGa=*Sv4Xm!r z+r#Mov~py>5fi~kdMHB|`g)tPGG_JoUV;0_IU>oFwq_mlg{9n z8(2@{oD&1nMGh^4ZweBfdglFk>K_7%cA#S~JU6cu>`C<+v9y<~ZkYF<7AUID`)N$O zHdQbe3nMmN*977%PQ+QORD1fKtfA2&ZTLH3o;1(_n54?_v3QmnvwNY0pr0J*o|Xcs zicc=93bec$1-=^XL4Z6}3g9ELrmAu0oS=&j3}e3cWa32>2cB}j)=~h3)Jrh?Q)L^ zQj_h6Gj>e4@lAc1goj?KDxhrYSZA>_iWjE-e@F325!O{Ba zDcdfb@8rw!ohl@hMQ7$!&EJ+=s+9to z<WnlSUBpiB1>o9Er!M-fzj)>7!KfW-$!3p za6;auOBxGk0WQkvXreVvte&^%&e&kG>ZR}Bykr5Xq413nKP6!OfX3-Z$M0+7J-i@7 zF*fLv<}*U|nLlwellHL>Ya&WCWfGVu6jtEDfoHjmo8!G(rBDEJ)&j^`xRi}>3SP^mWv9%1s z;0*){vgS)X%L?SA8nL9wEBuhcjf}jwGDNT7*2aAflfV89GaDBrdfu)sC!FpdJ2bAj zmYD2dmQpmD&9+e43Vt|$Ii2PxyP?$+J?Y0(e7qN z^yebKVjOLV7HWHhU2jcaQ=A9oT(K4bEnBo1s@pP6$9W5@$LpZrdF~g>-xHWeRk|Nr zRv9jV>^}ZV9K6)B^)ER)Tq21$czGhVV%?_UgVyiclR6N}S+LHUZujH_PC_;3x)hXw zZ`PdO>7pClQlKYvcbZEcWDD|9HWx`BUIA{ib?R(EF8(2j%BcKA`1EvUxsI`3PewXK zutDcB2*fuft_41FoUZV*eSbg>#Og=X3u;cx?*ss;PWnq=jSkvO{f}F*vHaV#(3XfZ zQYCF(#tAK>7mNk`qNRiTUOfh-<*^K^Mx#Q09w_+>NTZjXY2Y4&w<*Uq;0H!$wC^@{ z<*LS+s|auAtr){2=INjYMWQmVM<8+fV@B$xV46bN)c zTHNAGfm7GOdW7&W-6opBySkTuiPIOc_fb_(E8?ZbLwGj2sJxW-Ye$5XbxBwPV4N3| zbFnW*wj|g>92GJRqM;y_UC6W+>F(v^b-U7!cZv0s8R882zr=~* z%(ma1qy!bp%TJk`lzT;|j%41Ms=SQB%Vf{@>vv58^XL5Rbt%6b?KR1Ky@eQg1qA$8 zdMO2dYpODEy}40wYYY*4`rs4Q`L3d#?1_PWt*$MK)a%sXb`)J-u|2h~B%_RPJq0f? zNrN~ejwJ1Z9=8G7Bv5hEw$c9-uH)V)AGaoKv5B&TH#Fk%LO(asaldk1iFz5iZ6&}v zOA7mFLq-faKo%nD`psLlj#m?Bge3(duu+OdzdsSSL;CG$h?uYU573mgzU)%3jqS-v zu5kmR8tV}@h87*a;^D59NG-Tlfoz?~TMeG?u4auQqf-0D_Z40$ zrat1zWr*7`KEZM>B-z9{DLVI}MJhALTCY0~p~$ z{zCCUzDl?bw_HRe@sD^``oiHL7(&)A{GDw+BCsZ#l0)@WRV~)o4ttQitjS}x2wc}H z0xvktoHST<_Ct*feAF1(`!kas9Jo37=_Y=mV+dID=0Cbs{AUK?Uo67^jZgG{)B!Z! z*nT1O$cY_>j{TNO%YyCigfEYV?u70n@39T~2f@G;G&dftGjH6IDkYlx?pt^D`wv3Y zNk&3LXP^Ti?(Gckzn1$8ivUHBTUSgWdEOiK{nujAs$+b+JH(}w#qvtG^K+8J%eV-2 zQm20#>SF(!?LGVovv4@$T<0pt42$^P2qdD+7#&mHdo!}nH7LrRR9Zp@r?u@}rs2k3 zwgP{`z;5D*?F6yoOs4d{MHYjz+1?aeAK5Zr>`F&cWC&EmS`c_9!%MZ4Bgx)Gi=qZ& zfD$EG&10PNRf0NdZe&WVyZ^-+=SL0ZnpS=%tG$8RTmXz!HE}e>3Ok>utQ4+$U;3 zFC_+=ep?0d&H&=}njAF)NUoJac)xHtDc_Zpvcei6=Z zPGxLQL`i6gYz{;OvL5*y=!9!Dgc^TL)y!%R{?TTGhz3RMn<#c}N5UKIf$Xuv_Vt$1 z8RDXR-p|3h!e$9K_%TXSU%%Xp^V`RUG%-fUej&i)RWOyR%)R`#&ZJuZY*?yF_`fn! zoa@7W3S1Ji8S6p=0cHAczsz-3ru)7dy!e&z{XHrxvA+u*IQ5B=3PE>H#>8695_gBu zi7O`o#G^u)#1&%V0<_qZ4OQN%sdy1Kwh*|Cc>;XVp>Eq$_?nm+8|MTvdSBc3Esk8- zm93w-SX;!Xr##sA?|muT(j_f{SM)27y3In(7>Q}(l7gK-1ShAEddHrKU*cD&qubVZ zNhw4qfe4_fq^?Gox8ic}dZyiFOJSPB00>$bZ(#dLO_+A&>OJ!Dq`G|m&T5;)gqeF9 zPZ^>KH*q_ha$r;=M#`-e0A0(PHYo3gc8Y zGMHiJSur`uey#NtE!@|A!R1JL8aw@-z3#@b%8U@X#%Wait03O9z-sNs)?7KYSCO#` z6)T?YnG8(4b8c+Pozx4i%Zuw>cxMjNmIqT)_*Rp_jqZKnZG0A;--2_XDKz^+c0&GIqmR zaPgVhI9~AOpfg?Sk&Vs{^H zQR|LE6cN5BnwtzZb(*(;aAZ(z4Kpa zJHk0_@L^N#9q=Fp?O5ZlA5U%`QivWqT2~Q3QQQ@RTd+_r4+Y2pA6w#lG_eGe=#iHD z_i*aNMn0Y#c#uUqsxapHMKM1RRH&rNC5~i|6&IovB1pih&9*hfhH0sqFNE(mfaNiP zz8VQBv-aw+AJ&-t6C)Jp{n?!rV3l4WQjAr&WpU7>yo7Y^ z?-UMwp3E)j;g;s4tCLl^MlTGssel74N(B+KX zrs+KU6hSZCnWmCPrKD)Q37h~+pxHt_+>H?A6k@P)Qk^SNM-j!n-!9X2tSk7! zz{@Uph1x8b{4k@l#dJs#PYXnKoyCrZ;AR?LRU08lVlO)Bm!W&MucYUIS~#CCKtET3 zd+(ZbNvbU47fg?Ga>Y%}uD-8aU5nq`79wcWBbeyuBv9%DD2uo?wu0T6G_SMX>Ajg*@N#{-UwLZP5F$BX@4VX8l z_I49ba-(tPY45hLipi%`g6cGcs-XIL!V^A&4y8{}+;8%99q4*pY2I)RmcPgAm(16^ zjH1DpvQ=b)viuX!ai|{d{o<&A2o@?+$JkC&EU$Y!8~RDwVT@Y>yVbgC4_}OLMh?VwQ?L{6fjvzF&B6GWIrXl7*HLq;BmX{bX!uhz>(ypNQxvHfxQ!3E?F8CU1St5JWbNi}N9~E(?q`0xX zLnSIVem7N59^Y@SW4f6iP|$jNAvp8Y%tJR7GJwf8CiV&G_P|>>)emORV##}aWVMJr z3#-<73vT#1yWCiB@G(T9PWcr3L|Fx66^X+vnayO&|1C(_7P}+(Bhy=h{6(5^F)rsU z_^YDRly(ID(H>}+IxS)hEaPIOWK)=I7KsWqH68iztAQ)_v$o_k?PW%%D z=y;1_G@3qWiY4*kc(Q#wXfgG8r`2f z0Vo3*6OYqIY45(1wL*cN3SX^#+0GkQ?*aR{ceqg9W}5P@UZ^Yd)i&R$pc)SK-Pc@* zmc&Dl(n+o)OKWsj$;X7Xgk}sd%fMZ@TchATAQEfm={$q) zb7Fj$tTLA65}e5POs{<`7v(bVB_1XjPjw=vX@D|ezwRO%Y#VGZHlooPEnC*U!GRXe z2j$0x&;W-*2(-jaS$kbJt(PG4H9@og_A9yI^MUfauTfOr1<%7rm!x*5PF{L`ENE&q zi_d(Ak z6P5t?BL$HcFfo`f^B<+4u9#Y{W4F!}fOr=nxkffm2&?9*v4Ft-!KSWn`XpUiQl_lVvD%+Mmpvk7MaW9C~hh4jAJI8L5$> zTcTs8Pc{P2G77=m6j!czA6JEZ7E=_Su*x#M_WtqJIyk~*LUf|C-Bvq~bJ^LkS46ib z4G8?vtFx<{(I&~v=g49mv}w$e5jsYyd<$A-B$H2*%?*~bF&q!x2u?Tqp)iD4=d=oc z7UF_D!UFh9oSB2)kTF`f)d^NC-yfvY4I%wEcOUs%+KT$1kmIK_cM9(%c9o~ptv(yc z5|OJ7gWgN4wjGNK>Q_L z4eMq8IG?k`L{{g&P25h0S8q#)7x&)h-K=8n-c7!bm$dNMiGDh`U4gr`H7Z_ygT|gU zT2^I40p)kwczVP0oc@Cp8<6E4*zy&RZIj7!{iXDvjLec5M$VDSKDrXN%CSvS(B`GD z;>P!G_-B&LSM`B=;k|bHKF{&wV#~mB!m(@KKpf#6wB{H3QDOoGOzk{*=sv<`{JTzw zQA23A%anS7%P-tO-VI#KSbvfJn$=fABJ*qZBl1po1`|8?!!M4TKO+TY=3MAYhY%gY zuyxJxM>wx>R!H9+Y(sRI0jY-|Wv!Oy-f4;;a11)Oxwz`^@-rgJT8H$IJ-(&T#dKzl zvR}7l{&wEReVRxXGC4w+vgX* zR$Y>2AIsv6`r8^Dsh@P3;DCkea@vCQrFKN1u)^iZXFSusP)DSt?VB_2h$ItpV$Xs$Td&aovK_07Kb4iLSKX%DACFybpb!_j`M)%551D zq}m}@vk%cIxQrh6D=J6J5f_J?2xA6%u4q11gu|5t<4Kw)gXUX^iT>z5WA)OsciY=+FF(5wl`b9%REdHxr27h-`|MeYbaxrX0MobBh zk~lA8={S79RC`84@?#uzSlAa9bZv|jH|4kWL3AZ1+pce@EA8mv-AUFJ7-j7`DLvH_ z`|C)ss&eTwA{3;@Tbitk+vY(WAg+Qg-N}}y?!oU;AJ_7(a7K^zUGEfoBDU?hZi~=j z9T?tS;4ouly_7L$qzfTjP(`15yu@VaQVEkLP_JB{^fRYz7vlF@URkq_*iEr9nI_`o zA-Qpk+MY+PCj=>rPf}?i5w^;PdB?dmqAxn1Oa3D6;3(%7f)3&0K0tdj&b)X(Ci2wY z)7mUqb5FjrN!rFb@Fi_}q;!mDOOwnE_B5t=H7jisJVSX~KoA!R|GP3{j5>H%p3uM* zv=f1a8vaSJ}7lqyBA+OSQP8e_2lg&%zo<~AWQ@6WgXpuK?K+b? z{bZB{sx;gGL012-hLL);4PlEEpz&e6cZU&ow?NHWqU1j!YiBpC&r#v-hEZNVG|*nb zQ5s-^uWGs#JQ)1G?Hx#E|0pm(r{@XYq&dmOM!!XeT>V+~_wMG{U5~MXT9jO;uVZAK z6RQ&?b|uwmrKf0(T? zapcUEw*WiHN?=>KxjssZ zItgzIMAmGeL$(cy*x#i{Q^ieH>r1S2LlX`ct-~m5+vdkZpZ-aePa!fz$6{sL+I`|z5;P>RU-l1%wT0FWnr zkZiF-cnxp$pAVF(o+<(KY@H%Z1L>c5o?z9?@5lBJq*tZv|E=DUDi_4vhoL>%LFft6 z2OFXk=*M67J+^+*NGmL9DQ=C~lmw zDI2mUk_%P6TX;NiKwBi{kxYQSJ-s_rq2=q5Ms}N6{p3dEvCj?o17SM3#4HtZq6AqXIN3EP8l+b7iC4c#Pa?-2Q=|Af4)h4)-5=;1@6!Tq zCZH?P>$o;4MOXF&Q;I&>w5>?F)wXVvRZp-vh0;oGdgSr0clUmZ-XJCx-pfU6|zVN;NCE;5Flv5o`i<7b0`$7%Bp~@D+}wbug8@8aYfN3nnSQ zMYQx!K`1Dm)Ycg71tsd@At}KxO^`(GZZ)8P7imnx<&6vKs~l%fgO&qHJSy!FvT8wCzmH!$+H4P| z=sxcQC16XX1eq`_MeXw*t!N29iqYAE${mRUZS#@k2e7luVvxf61c}1cuz$Z=qA+&} zimKP`UER_UPW1^dXTIqjT>nZS%1?jNIwik)TXI@JVeW+Pxl{|SBe^jPqwJxH+Hajw zt2*v}h?)GToF6SM#=QjS>r)uYh}gez$5dQ-QydP5-#kj}sw?*)ShbN;&XxpOP%mJ^ z=c_dc@gT(-f*e&apgM_E<|K&B+2Fn<@x`AiGq@kiBS$T<<&m%oA-xT_DYV5WN%$Se zRbbD3z$yzhAS|R3LBJx6U+BWMA1)*=j%Im0nW}357V54n2hk{Zs`?wKa&wK*7!R;P zajtQfToW$;c75+xgqQIny2Fp&rLq1D$OIY<*Rkm4p5R$o)pt)z+%Zw zSdw`3+ijUBD>H0^ZlC5wM4&d+zDF?lal<%537?N~QL$K0Rmx-A;?Yy^VehK5B&@9s z-8eR?MK!wk3)V9Fq3_Y7%WkWEeV)Io{sTnTnwbSLYTJk0!c0C>Q@IGJvAxo=id$f~=0w$HTl%jmpB5U$v6LDCPrS+Fjn^u@LH;F~(uH>4<9~L<*9G9OgrLg!yD%Coe^W_ul)@ zBKqRSK{q)9k`ouZEl)@?{(5r@v4K(~d9!l&$S_mrM?!h79}#*2P{JMD+~Cu`UvDyj zit+7&!Yc`}KO_9Ia_)(VaBPao3CK}kU|*>;A#?}a*+4I^k9H*R>u7J3^PYl^0X&Cu zS?8I7qYM@lr3bfO4;yp3c}NO*U8-nvSTeC=Wa$i`CRB7tP1nC+JIHUWP0}T&ZiZ(~8}P z5n8}}RNS6wh(4BWopRAE{}5+ktl6DD;3s{vU0Cb@G2CvTf7_=tV4f|z8%6mZO+hvd z$TniHxDr{9D@$GxTbYE)SV+>TQi|GnVj*0WW2g>cL%+Ww%BH-oGoG)lcVKkU;Zn6z zZxJ_KvAQkSQI0#JQ}r2?@j)h-Ury(kO|LK!Le`ET6#>5-;)^;zOFltC*d6)_@lU`C zoh8+-tZhIHH6l~}sF>lGd?kH?z0E>4W?{_M8U8(-;T_A!pjIK5`FA?;t^<0GVPVD& z4{{+^f;=Ct{djF_I-gWA$~TloyI$L_tdCGysWPvryd%w&;!@^juwE!gN#CqhT?I&{ z^5&cm?Y$Q_QR!((zDQBPu$Ot0Oay#5;&lA>4N~8{`O0r}5tUBd?RzoM+W)$ z79TDad@hq7e_FV@$>`0{aCbGh9I1TUDC@UB>!nC`gC^s=ULh{LeGI9I*5++z~z1JPJ1Qz#bIqeFqjq4ZJV zo{4;qdw_mt`230*Gp;{Svk^De8k#h^2yOgX$I%9`cNP8=D~y zK=*ht*Mhri(#u=U*E{Q=1+7f&W^4``{=E&b6u^=eJr&#I>V)9Ct_Wju$K*?>~NN27}O7#I=d zrB0Po{b7F5arcDK@ur~f9gJ)n$A-m~LUNV}AOq7jrVwfyk7Cl6H+brFIzWzH(|6I#E*kunyLM1?QG5JVkCHMjX2SSVLb!6$jcAy z@x$+y@+33dU2~f|2Mrt)Y_`g^MNu>esoF!#qKL|D1{JY3oLK|gxi=N*eZ#?8VH?DlJP zv|gGRwo_8sxJ(lKMePjz5ekK)`*Y`&hiu*sS`euIw6IuWIgH99!`pEi0t(ZCO7nl^ zaQ|%&xqNjSTh!BK5j3dX=&X{t!fY8L&XZ}LoJSMWDBf^MlK#z_8Cy)HX{d}4T`WJI z?9xM~{8rr+#_qP7sIQ*k#g$`33)OW_^hFUU#S`4@1^4RvB3CaD_pfQFts&rsqDZxr zkvYqb?YjjC!V93p|2G(Bau=f|-XBbnb#l$!*Vvl$f31a5wIE{c91eHe2KeeT67{xu zWu{iQ;evj4-}Msb;i?2oZ15jz2#G`&X>n7JByce}NeV);b^2^Pu@_o`!>4+%!f~nN z2{toJITQ|6go!RU9zBqM@rCUE*nCQxuZeJsqH8N|I9gU@y~ch)1Ts?UX+;Z(=rW%X zz@{q|I;m-7FaZkC$wX?{oY>Q?0SMV!dAUTBa9*b5bJ!8KkB&E7`3dmK{9>|VBKxVJ zp=nCVy1uZVB%k9%`l4l-DQ?JfE-4)+em|xp2quRhOy^jrtIx6>GNDvZiN0EM10UA&Qd;23WG1;zE`y7ZJOGgXS31t2n_<1e zZNSj(-p`n0j+*<;=GeP^oJ7je?R}C%VvJmQ2&wM)gL#UZG+z+ef}$+F(96mA&3n$M zrn2ns;4E=Y*Q>m7sMCRhn0qOlsn~k|e(MaK)SUMu+G%h1w)16Uuj54->BQNU6v)%7 zjInP)Xmtx;U7`}_xZXFqbeiHp&>@`!yCKsOY2mMKG&NazSr z5}t1+z9jfNJQj_kl5NGr2Fb!vug7K*A<3F#bgJN2tAAJrk28q9Oc7s$KqJu5Dl_T+M@m+n|u^X+FU@m9_XH?t@elQW%usfPywyhDekf zVLd`zAn`-{;=yK#>fAvXh&qW22fII~|+jFR=Y4cH5w%Gu@#f*I* ze#KT{mt8M6-9!@9T;Y1ImT`85mv9pB6HY>9z%!TOoHaT2JM)?4{3iPj<(<_NAC-o5 zX!}PK0QlRTukXr3A@E?NJ6rrde8?1p6>x$6TXr`39AV~ZCKlN;xRvn)qIQrwVP=>r zb(UnAR*ix_sUaM5*o;VaL*9H*Z-uO|O0`7nlyxx|LXUcCGqZTwWi&@vPzknH7@W=C zekgU*rhcY62#BxqW7gdZH8Pn^sH=%-i%xCP(-NAtOMVUCiqc)Pn2nzzb^)^w&b}+e zXk_&NEkQw)`knh&O6p6Qr8wguiI0t~)ku=P@X~!Q+p_L_A=$~aS$sKu76OdSuiP=v zB<#;(&QvqYyh(DA$GkPAy{H?M1Olg>G^7Yl$9JdaAIFiId{ztqEc6r+UtUW_r9P$!%As&+&@fyr!BaVSfkHSbb$@d;+Bjz)@XU zeVok(>f%!!sB+h2e)&@lj&TuuW#?iC$)jTzE@yA_k(h#{;!}Ok`m;Cw{5t|Mtvh-4 znzVitDo7d*4+q1~)7|?v3$Bl*;2lgmjVI^_skE-6Qpkif^5!J$5A2^lhcH2Xyt~*S zf8%mSI4X-V5UswaCCSanj8qmZc2iDF6ptb_Sb_~@rpf}U?WSN=U_?u23jM0s!H2G* zpv(Eu%f$FP%Nk57%e1;8Wwt{f->%=pRkk#wNeqG##v^l~uDmK>Jg_4w#ZY^osHd!e z_AtTn?&g_I|6CKW+trUYEk{>dFfUH$YbRlYGWSd`d3LfRCfK2p0Q>A*cK^C8g|CbU z6LB}xg^jk=J9=qS%Njqfpq)yT+TasTB`isVdNHFDTp)>qy{4Ljnn4D)u{8?Y zvL0{LlTR)~qbaygMGDQGa)rfK2j1^p!nKM;h{D!lLhgqJwU=jNm55d2U+JdmyiyHk9b=_6-OBpHEs@J2 zOp(Mn-@ejrP5MnxzR37Rsx4`lo*qY`GOxK__28&>D^@HTjXR)^4IGR0$Y3ZV#pr3^ z-LmNgFQrhF@o;8zCcR%x^F!w%O`=0(nR-8II~TiHrMC!l|bH{;kLvsRB zc_@-Fdt9ZyfECzBp;^evCyw>0O}_ru`x2LWz%mMx2Sh)2QmS~TV80ct35!9_y*M>V5FlQl6Q|-YQ zMi?Mj;{e9c*f5)FA^vi?}~P5BmV_y)G$T4r{$Y|4#6g6UgcbKHc~MS)3Wa7ckIIL_0wR zXSCzQ@5%lTP?X>8!QWS`r^#Y8{R8x`g(d#EiQ8f^DDbCeQpnFgK--zGo`QhTbJzg^ zM(9GhG!1f!AK;g~0W#o3z^rEK6)02y>>-yEkajDL{OTF!c3fe#iz{9J?v)fX>klzp zE+e3UQUGwl=z;LB|3K-f+Pp$Ma=iqY3nJYF_!{aO=WSERM@}r+bEGF94G};5aLUc@ z#2M-H`B3*2RF?78Pn&^0!EA~VM>xriej#yOP&@RQ;;%hCguDNVVWMk3Uo--#nlfA+ z{QHqc|MLVKHz5~9qx~$6q(Ur6|EeDRAsLK$zZ%$U;CwjytR4x8HAN3Azq!oU8nCz@ zLUcdJ-!Y|*(HNyPaq9$jzww{D|MzpO7nN&m3ZRT`^NZ@dyt3^MDn={vm|^WGgRU}O z54~CQb*yXU3R)7H4JgAmO-?~C!xHksn@<79Lb}_2|2na`|2p04v#CqB_+x4C$Oem1 z9F#E#MElK0zV+(<&6#NF?5*b^m)pKSV=(+g<$P$r48#>pq_kgarRD4z2$`99-s-rgDaxO4{koi_hWT zZz_uW0l-%+eagq0y{Nk?VbA9{24+C!;mbQg(lnvLTNN7QKJOP$N#IxD{`&<^ex^rK z89xH2|H_PR_f+`qEJwF~xmo>9m`%O^_mXA;9zPywivr$&HwrkmC-av;=#wHrO2^+W z;@@vx*9`0#8yDW6i1U}dOhsMO9-Ro)*g!cgHQypnljw+j(nX?2&0rZ6Z&~f zYC3jhHMkW1d2juvhf8aiH)d%MrR3K8J!TR43yfd}3HoaX^tH9=BvLf-W!q`~v7EIJ zv&?y?6gEBd#7+IegT&(Eyo$J7_Wyo^4R*FWbuFpON?}G|!iXEP%~{p|2Zmo--@l7% z!`VvCl8eXk)(F30;)i4R1Vv!+qt~l|Fh`(n#~7zxZ(seoV@6UdN;xW>8{g(x3@5Eosg_e>QCx z_~l00gE1~pnDuHU`SHB+gPP#}rZ_=4Lfegp46oNAI}Q=_Bm?hm%j z*Hn+qgQwGVIpYT_*<5(9g82eEv{Xpg1}K3FO+{dvel^qgv8+lZTI$TjFyr7#PJXG}rSyR)ipmM`e*bBnP1I%+bAh~t zlmNc&^7F3z=aL%m8S^VW6*X4mD7F5<{tzf~J=&JsO`y6E7|O`+^> z+bZUvWihO)?|A+Foe1qBZyDpqxHu`;zpQmdd~$x2(>#JITe5K9F$#1-W%s?@Z>J#^ z_>pDqu}M1-&*1S~o_Y$=8(7sydqC4`i3rQUgZUCQ5|OsRH(wCD=#)r=qPzoM&+T01 zw?Jb)S5zdCM-Y`iazB(xo8*~fMw9Bwr%2mNN>yM3<-PQ@qx6(hdG7seB~pY5+78$# zC(3XPkW*@IFHvM_yP#dv!1FzquUk!<(v%$MHjX zh>r)rN~_L!iaDwX@@q8k{YajAk`eOZ(eJz>=sKUp>Ry+;%c8wDh42aw=9)bR6T^x5 zfM$rIVCrdBy<9x-K7GUJP`OmY78lI#oZyP;#&>T!F?=5Ugo6j`BV1bDLxjoTDE{qx z=Vv@cfdsxGf=$efPBrn^jSxG2`o7-neYR;=y=eImEGEmd=OmNn0nnLXR>|neJ_A@T zr>$6OMBNiJTx42FOiIX-Rt~Sw&i{ib*abCDTq=#`gg3R=t5gDBnTRi=Js8{wmg4<0 zbiS?BKu8>~Y*!I`$Z(}+3jX9uP-FdSW!-HoJAi&Kp>kVxx_&cyEpB~SG!=|@HKQ&O zq+WJ3l4^GnLr`nhsoReZR_!X~px}(%x!^9B9oEi#niQxLeXoNNl$(rjpM#{slOr_XR6D8Xm4Fp8Se9tJI^SOT;wg4hV)#~HwDZ>s z{g+qSRMQ~?7R=}aYYK4yJUgY68vPP<_5jq}$i0*ZXE^aF-Q=N0&9;_`z>#c4Ajv(R zhl{LU3L($56M4?O$z=l_G0TksakNoPkhrCAmWcB9b$%DyCP%d2t`Hipv0QEny2|0H z5|S$_p?j9GM;4NSqj`FH0At2WK}?w>jQFt2qvjec?i%E5x^*QoR1vf zn{nbLc*6!o=B?5jSQ-Sx*Fy4gR7Vl)_*rk<(i|)~-_EC`%B@bqM>eE;d5}DNSyIYw zI}oYGW?25!~G& zxVt;7+w1K8t@Bmgz3bFI_x|XrQB*h8vt{&n-^cu*fC|U>vg8|#DzT|5U<-`8|hHoF!NEa)=G+q2W)7t{F+93 z9QZ`fJ@yc#Ia71;QYP68zgijL%{6DsTgsrSmnGiAZh9X%j^IoEX_aCJqc4~8D4;v7 zo;A&r-Gp=2WVZY}E9IadIxg)6e$~{+yw-&2+jQRo^CRK+)V(D+@asz`(<4> zW_5UgtI}@y+@b1yyOX=Gr^q4Aaf0P{X^43Iv6ik+n#Dwz8Ymf|v3|H)7gQ^MVk>cn zjw@w9*R`^^+KI@``PgdWIcC!kP4Y9@;vI?rSXLu}c$e}Ayew8GbV@82dXJya2-gD3 z;G!^eAi`!VR<<|B4>I<;5`N-NBB zcakpKV!R5f0eQ%_(9VU*Ih|$tJGLwH!X%Uc);0HPziKDgl$TT zQGLR39gVKJA3NIFnD{{92_AT+Lfehyl{$#wSf?%$n-GmSfSX=78*NLge;j&D5p^;WUYd@@)!( zt-oqAQm|{OFG8#>V-nh6^ZA}IA9Iy0j((04()O%3HYPe$7Y(0Hk1rhuq zVjC^R{&pOQe8N)Db*sl2yXz6GeY+dq49LD|ag&R|=Iq?l)Kf*dGNFkikI%I=jtr7< z%DvM7;XDR0=A`2fzSyoZIZM15AQgV@5&FUv?S-M}cBAUDEBIXVfpCx_#*m}OT@}$h zUNSI`n2mQ^_{pPWVoR51Hc|C$tTyJ7n1|oqXU$5z|E9`GB3$*gU}%p3uBL}is>94RGUGd|L+cx|MKuedZ=B+ zt&quu{#_=5=OTg3r0R%sIM+4A!24g29@jARfVEe-!5VGKE(XQQuyoKz-m(EE|8YfC z(a-*9H`R9kGEaswuWtC6G0a%Hg(x*@q@FS^wn|8u)26C@E~Hp$Ojy90+`d1&I$Vf- zbtS##Jw%lYHlXfmTyT3-A@}+%>;k%_y1{DUY0#6W%;u>h3?~Z~7AHa%tMuY{2-dCc zn_1MskHU%XEO?%lekXL{_tLtbp!KZ zZ|*NjgI**Fw0KKGpr11`6h1xeTMd#-9Gqq|3alF%XyJZu`iw{)J z+H@SRxd7zQ*&VTHWI3MjFObXY%p3N^s=lH<%}@c|+Ur}=GVBb+KSDmujDOSjk!SrM z9Fo_)dG?*67`%d|vI5p60h)f3R)&3Ml$X^v-glIV`Ei1n1{1-n{>6geUu_WChC^T; z3iFC9?U>H@1T_qNeY)Xp#}Af{y`8wN zs#>f{ocv=K$tf+R)!GrWh7&)IEv=|&-{+x)I@algOt7=PdV|G-TbDPTA1v1=aUGXq zjf{VA=2`Y+U9+hXqO^Z+Q|I>=s50?d2Lu^BdxY(#NTZhy=`4`GetxypqDCrSJe7cfna#S^vJBJ1{p2E!S1zD{J7cEirtWT$ zs}j&11sBbVTc9^qxSlr@tmfqxj7a*uswvD^sjUUCTL>Z&dPe#kTc&T)XN}NnTqqL# ztrHN3E|vF3^5yih9b8E6O;YYHTh3~PZ2VVF}g zp${n~eh#6GJ1Sr+O3(Z5tWNR#;|Cbi?k`RE2pvLt?DPqbrgz_e-(e9R)1do+@Zm_h43OD;^^+0=}2x3AD~_)I>~$G2}G{pL4iA5`V;8(O`Vz#u6%DIZi1p!q17p|cR6w6Q|IUnkai5PbqMb}tqg!-? zgcZ8vdC@fF8rD8H@1Cv4!6LU>&v=PHWR!DtXbF~Rw>#^9WdW4>F9jFSRbeV@Aea@% zJeOd)Kv#swQu%7jnF(Z0;A_&kb1?$UHCKsZ%EsQ&olp3^m!okpf^mOkNKE?6Avnfu zJ=>(2t0fPC}&a0G=d;$3v&s!pZ(#37po#az|qAB23 zdW!A31hUvbQQ&@ZUa!~noc%WZmK{oofR)r`Q?1)EymzPzN6m~4 z_fFc@p5%zvGRIZ()Kf-p`y5pp9OjO) z(q5?oS1PJS@(AX!;x}ZrK7SfarV^R8ocb5^O*8PjxqH)mf`MG$;47Uf@@rbhqVVCa zm5Wm6Tb(MMq94?`&wn&Udly7GhlHw_#>Y?RB5SnR9j*<&L6xuEqlzN=9%+?ShWcyF zvm4nKYIT;zSUE*Ks{<K=&%BA+#+U!Y&MD6}==C!&)lZ;%_8+?$CivIyk z91RdG7iE@ILH~w%V`78+P646}yczFVgrz_<^xc7+3ejG9aKyH*pU&sAh+@+6;0~p2 zdG||;2J_(FE3GTSswD{1L2ZQe+X9)cB#kGpbWk_yQ2Zq-Ftv2sT%%8_?SUk&iz-;? zim)?5zxD#5^Am|?8qUS~`ME&jNltf#BC~nVDo_~)GjjXW5Rj)W=NK=Sg;gM%hxffP zC#pAo$>DPD5)+GKB%Lu!4Ez@d_tGW=nmh9>Y<`4=-r=U{4%7P>i#@{ z`z{8Dtjj;*fxDG3Yo2?a7BucNbao5FMW!+?NA$lF_o{m!{@QBS{VeO??0Du#K$x}^ z;D;4|;d21aB6Zan&R+XERaRW$vXEgrz63x_KdoOFlE?aUHe%VqCqU2TEOv`f(P^=( zD9i3JmV+aN@kw)A@P_9y=mBY{f`HyrXkB~yWY3(5vs~_mPqYXeipPQ{^m_bg_gldyG{x<7m*sdx03sl~Ym5BX>!y@x!F+kccvuj8jhW>3f8qY~5 zDf%f95Hwah@SL3O5FB-KUG`YJip+B`mS_0_7573#%wDb0l)WOZtwht&ddl(N^Z#7Ex!+B?#xBh8&nN3z)3qJ_98eEMM|ahN1;_S7$4o*z4(!c z`lorNUNFP&!CC<^y#Y4MOUSEw0RLECNf7grBS*Dat9}J&Rm@Eg0^$F}s9xnkp zdtA3st?$)jQ7(&GGX0{VA8;Qb*^Pt!JSp#U@-s`E1fnb7i2P|8%1MP`olsSZ?P5ar;?@g4yewo5DUG~YY zU);{}s$rUXn_Wi!6RPP`?1dt;M#Kt)DH}a*KHD^QK@U&uM#vF;44|y>?RWl|(Ad?t zM{zh!^ko-nAg_#S23ZzS_VNbXr-oU(s`um3Rt7gR6M%=Virz0)R=ceR9`1b5Gza-2 zO)N~EHb$kR{wea@K62IDS7{_>`TnOx7`MbRozf5gp|!+;>m%I5!qjJo#QA!$l(zobzhv+_L!H+xss-T0D^t2g_^*(o;~WB z%DP&7TOO%|p;7Vu{;vnVY4gRq2-v%iaS6y6@bKQ)wfL#ZF&iVzBO_NC7-*vp`!V6P zS$8iCKVPUY116GVUmt<#aZd15e(R+sOM}9HRy>R}jOXlQ=-%916ak}t57&Y=CgMwJ z%qU3T?{i+*;5di!rXEI9(*1i6l=&-V=Ju0kF%?*dM4cs7pe#QAZS@zv!t`$G=o4Q! zd~UP-Pn}I-*J8hA$7RU;U8m!x%$*3MydZegjzZF@8-oxmmT7p|KSTKA0X^8z{vjvk zZ^A;k)GwpkW7lq;r{}R9Gcj$INOY|_>unjmJ#JBeX=r}XHXRlx??|hK$9cS(0U>Xy zN}EsB9~RUH9eJ;vT0vd$19)G^K3)E%dC7mne2ubk*#636S^vxnbP7le3)A}98*fDx ztIe`3zy$q<5PB*WZ`j-I3&4`a**||;fzNSur9KKD(W?K}WmLnuRG9BP1IXzOD#QXD zi2ncB{^e+6`Og4^b@>K7+H1x;wn_gQ*+Ac=QhhPpZ5WIfx;T{q2gUu`$XV*M@wuCS z3WyuC7w&7S1L8!h_mYTMd^fC1y1=t4jKrVRY!i$JV*ncrIT&&%G5-EHzZhj=IE@$u z`h;aUttrxxR&5n*8RRPq-<=EJjNkcDVKLFdS<|o8awcqqh6O|D3fcb7vi>J@ z*J}PB&zeB43Iz$k&!9Y@eSNsWPTwz`+49W<`!qcJ#Kgl(It3Eyb~M2y%KV?c6O#kkw3pWUp? z*p21jqF?k>Wk4f1l1k+0IPLDh5il z!E;6?d@7NvhUQl|ByYS@hsgn=_{4iE6Oqsz%`C8NU8oOH06y#+VESN>%1Ep9I(r{a z0X3V_Uoeh_X za;Ao@4LY70cpEc>kGr=5IV&CFWf7S(F1N*^!ZrTrYM^xuJ}`N<_%2#n>Q`*Z8p&C6 z0Xr=kwM{2!wFwU72cd$Erm;{379tN*L!>T?v%TTbdwMs#U;|

wjK)^zNoC`k3V8 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/src/lib/zed-ros2-wrapper/zed_components/CMakeLists.txt b/src/lib/zed-ros2-wrapper/zed_components/CMakeLists.txt new file mode 100644 index 0000000000..df6b8fa2eb --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/CMakeLists.txt @@ -0,0 +1,332 @@ +cmake_minimum_required(VERSION 3.8) +project(zed_components) + +################################################ +## Generate symbols for IDE indexer (VSCode) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +################################################ +# Check the ROS2 version + +set(ROS2_FOUND FALSE) +if(DEFINED ENV{ROS_DISTRO}) + set(FOUND_ROS2_DISTRO $ENV{ROS_DISTRO}) + set(ROS2_FOUND TRUE) + #message("* Found ROS2 ${FOUND_ROS2_DISTRO}") +else() + message("* ROS2 distro variable not set. Trying to figure it out...") + set(ROS2_DISTROS "ardent;bouncy;crystal;dashing;eloquent;foxy;galactic;humble;iron;jazzy;kilted;rolling") + set(ROS2_FOUND FALSE) + foreach(distro ${ROS2_DISTROS}) + if(NOT ROS2_FOUND) + find_path(RCLCPP_H rclcpp.hpp PATHS /opt/ros/${distro}/include/rclcpp) + if(RCLCPP_H) + #message("* Found ROS2 ${distro}") + set(FOUND_ROS2_DISTRO ${distro}) + set(ROS2_FOUND TRUE) + endif() + endif() + endforeach() +endif() + +if(ROS2_FOUND) + if(${FOUND_ROS2_DISTRO} STREQUAL "foxy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_FOXY) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "humble") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_HUMBLE) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "iron") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_IRON) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "jazzy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_JAZZY) + else() + message("*** WARNING *** Unsupported ROS2 ${FOUND_ROS2_DISTRO}. '${PROJECT_NAME}' may not work correctly.") + endif() +else() + message("*** WARNING *** ROS2 distro is unknown. This package could not work correctly.") +endif() +################################################ + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++17 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# if CMAKE_BUILD_TYPE is not specified, take 'Release' as default +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +if(CMAKE_BUILD_TYPE MATCHES Release) + #message(" * Release Mode") + add_compile_options(-Wno-deprecated-declarations) +endif() + +if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + #message(" * Release with Debug Info Mode") + add_compile_options(-Wno-deprecated-declarations) +endif() + +if(CMAKE_BUILD_TYPE MATCHES Debug) + message(" * Debug Mode") +endif() + +############################################# +# Dependencies +find_package(nlohmann_json REQUIRED) +find_package(ZED REQUIRED) + +exec_program(uname ARGS -p OUTPUT_VARIABLE CMAKE_SYSTEM_NAME2) +if(CMAKE_SYSTEM_NAME2 MATCHES "aarch64") # Jetson TX + set(CUDA_USE_STATIC_CUDA_RUNTIME OFF) +endif() + +find_package(CUDA REQUIRED) + +set(DEPENDENCIES + rclcpp + rclcpp_components + image_transport + builtin_interfaces + std_msgs + rosgraph_msgs + tf2 + tf2_ros + tf2_geometry_msgs + geometry_msgs + nav_msgs + nmea_msgs + geographic_msgs + sensor_msgs + stereo_msgs + zed_msgs + std_srvs + diagnostic_msgs + diagnostic_updater + visualization_msgs + shape_msgs + robot_localization + backward_ros +) + +find_package(ament_cmake_auto REQUIRED) +ament_auto_find_build_dependencies() + +find_package(rcutils REQUIRED) +find_package(zed_msgs) +find_package(rclcpp REQUIRED) +find_package(rclcpp_components REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(std_msgs REQUIRED) +find_package(rosgraph_msgs REQUIRED) +find_package(tf2 REQUIRED) +find_package(tf2_ros REQUIRED) +find_package(tf2_geometry_msgs REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(nav_msgs REQUIRED) +find_package(nmea_msgs REQUIRED) +find_package(geographic_msgs REQUIRED) +find_package(sensor_msgs REQUIRED) +find_package(stereo_msgs REQUIRED) +find_package(image_transport REQUIRED) +find_package(std_srvs REQUIRED) +find_package(diagnostic_msgs REQUIRED) +find_package(diagnostic_updater REQUIRED) +find_package(visualization_msgs REQUIRED) +find_package(shape_msgs REQUIRED) +find_package(robot_localization REQUIRED) + +# Debug +find_package(backward_ros REQUIRED) + +# Check ISAAC ROS Nitros availability +find_package(isaac_ros_common QUIET) +if(isaac_ros_common_FOUND) + find_package(isaac_ros_nitros) + if(isaac_ros_nitros_FOUND) + find_package(isaac_ros_managed_nitros QUIET) + if(isaac_ros_managed_nitros_FOUND) + find_package(isaac_ros_nitros_image_type QUIET) + if(isaac_ros_nitros_image_type_FOUND) + list(APPEND DEPENDENCIES isaac_ros_common) + list(APPEND DEPENDENCIES isaac_ros_nitros) + list(APPEND DEPENDENCIES isaac_ros_managed_nitros) + list(APPEND DEPENDENCIES isaac_ros_nitros_image_type) + add_definitions(-DFOUND_ISAAC_ROS_NITROS) + message(" * ISAAC ROS Nitros transport is available") + else() + message(WARNING " * 'isaac_ros_nitros_image_type' not found, ISAAC ROS NITROS transport will not be available.") + endif() + else() + message(WARNING " * 'isaac_ros_managed_nitros' not found, ISAAC ROS NITROS transport will not be available.") + endif() + else() + message(WARNING " * 'isaac_ros_nitros' not found, ISAAC ROS NITROS transport will not be available.") + endif() +#else() +# message(" * 'isaac_ros_common' not found, ISAAC ROS NITROS transport will not be available.") +endif() + +# Check Point Cloud Transport availability +find_package(point_cloud_transport QUIET) +if(point_cloud_transport_FOUND) + list(APPEND DEPENDENCIES point_cloud_transport) + message(" * Point Cloud Transport is available") + add_definitions(-DFOUND_POINT_CLOUD_TRANSPORT) +endif() + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + ament_lint_auto_find_test_dependencies() +endif() + +############################################################################### +#Add all files in subdirectories of the project in +# a dummy_target so qtcreator have access to all files +file(GLOB_RECURSE all_files ${CMAKE_CURRENT_SOURCE_DIR}/*) +add_custom_target(all_${PROJECT_NAME}_files SOURCES ${all_files}) + +############################################################################### +# LIBS + + +# create ament index resource which references the libraries in the binary dir +set(node_plugins "") + +link_directories(${ZED_LIBRARY_DIR}) +link_directories(${CUDA_LIBRARY_DIRS}) + +set(ZED_LIBS + ${ZED_LIBRARIES} + ${CUDA_LIBRARIES} +) + +############################################################################### +# SOURCES +set(SL_TOOLS_INC + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include/sl_tools.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include/sl_win_avg.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include/sl_logging.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include/gnss_replay.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include/sl_types.hpp +) + +set(SL_TOOLS_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/src/sl_tools.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/src/sl_win_avg.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/src/gnss_replay.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/src/sl_types.cpp +) + +set(ZED_CAMERA_INC + ${CMAKE_CURRENT_SOURCE_DIR}/src/include/visibility_control.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/include/sl_version.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera/include/zed_camera_component.hpp +) + +set(ZED_CAMERA_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera/src/zed_camera_component_main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera/src/zed_camera_component_video_depth.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera/src/zed_camera_component_objdet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera/src/zed_camera_component_bodytrk.cpp +) + +set(ZED_CAMERA_ONE_INC + ${CMAKE_CURRENT_SOURCE_DIR}/src/include/visibility_control.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/include/sl_version.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera_one/include/zed_camera_one_component.hpp +) + +set(ZED_CAMERA_ONE_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera_one/src/zed_camera_one_component_main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera_one/src/zed_camera_one_component_sensors.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera_one/src/zed_camera_one_component_video.cpp +) +############################################################################### +# Bin and Install + +# ZED Camera Component +add_library(zed_camera_component SHARED + ${SL_TOOLS_INC} + ${SL_TOOLS_SRC} + ${ZED_CAMERA_INC} + ${ZED_CAMERA_SRC} +) +target_include_directories(zed_camera_component PUBLIC + ${CUDA_INCLUDE_DIRS} + ${ZED_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}/src/include + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera/include + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include +) +target_compile_definitions(zed_camera_component + PRIVATE "COMPOSITION_BUILDING_DLL" +) +target_link_libraries(zed_camera_component + ${ZED_LIBS} +) +ament_target_dependencies(zed_camera_component + ${DEPENDENCIES} +) + +rclcpp_components_register_nodes(zed_camera_component "stereolabs::ZedCamera") +set(node_plugins "${node_plugins}stereolabs::ZedCamera;$\n") + +# ZED Camera One Component +add_library(zed_camera_one_component SHARED + ${SL_TOOLS_INC} + ${SL_TOOLS_SRC} + ${ZED_CAMERA_ONE_INC} + ${ZED_CAMERA_ONE_SRC} +) +target_include_directories(zed_camera_one_component PUBLIC + ${CUDA_INCLUDE_DIRS} + ${ZED_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}/src/include + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera_one/include + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include +) +target_compile_definitions(zed_camera_one_component + PRIVATE "COMPOSITION_BUILDING_DLL" +) +target_link_libraries(zed_camera_one_component + ${ZED_LIBS} +) +ament_target_dependencies(zed_camera_one_component + ${DEPENDENCIES} +) + +rclcpp_components_register_nodes(zed_camera_one_component "stereolabs::ZedCameraOne") +set(node_plugins "${node_plugins}stereolabs::ZedCameraOne;$\n") + +# Install components +install(TARGETS zed_camera_component zed_camera_one_component + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION lib/${PROJECT_NAME} +) + +# Install header files +install(DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera/include/ + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_camera_one/include/ + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/include/ + ${CMAKE_CURRENT_SOURCE_DIR}/src/include/ + DESTINATION include/${PROJECT_NAME}/ +) + +ament_export_include_directories(include) +ament_export_libraries( + zed_camera_component + zed_camera_one_component +) +ament_export_dependencies(${DEPENDENCIES}) +ament_package() diff --git a/src/lib/zed-ros2-wrapper/zed_components/package.xml b/src/lib/zed-ros2-wrapper/zed_components/package.xml new file mode 100644 index 0000000000..1e3407edfc --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/package.xml @@ -0,0 +1,59 @@ + + + + zed_components + 5.2.2 + Contains the main ROS 2 components to use a camera of the Stereolabs ZED family + STEREOLABS + Apache License 2.0 + https://www.stereolabs.com/ + https://github.com/stereolabs/zed-ros2-wrapper + https://github.com/stereolabs/zed-ros2-wrapper/issues + + ament_cmake + + ament_cmake_auto + + backward_ros + nlohmann-json-dev + zed_msgs + rclcpp + rclcpp_components + rcutils + builtin_interfaces + std_msgs + rosgraph_msgs + stereo_msgs + sensor_msgs + geometry_msgs + nav_msgs + nmea_msgs + geographic_msgs + tf2 + tf2_ros + tf2_geometry_msgs + image_transport + std_srvs + diagnostic_msgs + diagnostic_updater + visualization_msgs + robot_localization + + launch_ros + image_transport_plugins + compressed_image_transport + compressed_depth_image_transport + theora_image_transport + + ament_lint_auto + ament_cmake_copyright + ament_cmake_cppcheck + ament_cmake_lint_cmake + ament_cmake_pep257 + ament_cmake_uncrustify + ament_cmake_xmllint + + + ament_cmake + + diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/include/sl_version.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/include/sl_version.hpp new file mode 100644 index 0000000000..b71487f597 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/include/sl_version.hpp @@ -0,0 +1,33 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef VERSION_HPP_ +#define VERSION_HPP_ + +#include + +namespace stereolabs +{ +const size_t WRAPPER_MAJOR = 5; +const size_t WRAPPER_MINOR = 2; +const size_t WRAPPER_PATCH = 4; + +const size_t SDK_MAJOR_MIN_SUPP = 4; +const size_t SDK_MINOR_MIN_SUPP = 2; + +const size_t SDK_MAJOR_MAX_SUPP = 5; +const size_t SDK_MINOR_MAX_SUPP = 2; +} // namespace stereolabs + +#endif // VERSION_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/include/visibility_control.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/include/visibility_control.hpp new file mode 100644 index 0000000000..c5afeeb5d6 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/include/visibility_control.hpp @@ -0,0 +1,61 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef VISIBILITY_CONTROL_HPP_ +#define VISIBILITY_CONTROL_HPP_ + +/* *INDENT-OFF* */ +#ifdef __cplusplus +extern "C" { +#endif +/* *INDENT-ON* */ + +// This logic was borrowed (then namespaced) from the examples on the gcc wiki: +// https://gcc.gnu.org/wiki/Visibility + +#if defined _WIN32 || defined __CYGWIN__ +#ifdef __GNUC__ +#define ZED_COMPONENTS_EXPORT __attribute__((dllexport)) +#define ZED_COMPONENTS_IMPORT __attribute__((dllimport)) +#else +#define ZED_COMPONENTS_EXPORT __declspec(dllexport) +#define ZED_COMPONENTS_IMPORT __declspec(dllimport) +#endif +#ifdef ZED_COMPONENTS_BUILDING_DLL +#define ZED_COMPONENTS_PUBLIC ZED_COMPONENTS_EXPORT +#else +#define ZED_COMPONENTS_PUBLIC ZED_COMPONENTS_IMPORT +#endif +#define ZED_COMPONENTS_PUBLIC_TYPE ZED_COMPONENTS_PUBLIC +#define ZED_COMPONENTS_LOCAL +#else +#define ZED_COMPONENTS_EXPORT __attribute__((visibility("default"))) +#define ZED_COMPONENTS_IMPORT +#if __GNUC__ >= 4 +#define ZED_COMPONENTS_PUBLIC __attribute__((visibility("default"))) +#define ZED_COMPONENTS_LOCAL __attribute__((visibility("hidden"))) +#else +#define ZED_COMPONENTS_PUBLIC +#define ZED_COMPONENTS_LOCAL +#endif +#define ZED_COMPONENTS_PUBLIC_TYPE +#endif + +/* *INDENT-OFF* */ +#ifdef __cplusplus +} +#endif +/* *INDENT-ON* */ + +#endif // VISIBILITY_CONTROL_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/gnss_replay.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/gnss_replay.hpp new file mode 100644 index 0000000000..47460a4301 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/gnss_replay.hpp @@ -0,0 +1,38 @@ +#ifndef GPSD_Replay_H +#define GPSD_Replay_H + +#include +#include +#include + +namespace sl_tools +{ + +/** + * @brief GNSSReplay is a common interface that read GNSS saved data + */ +class GNSSReplay +{ +public: + explicit GNSSReplay(const std::shared_ptr & zed); + ~GNSSReplay(); + bool initialize(); + void close(); + + sl::FUSION_ERROR_CODE grab(sl::GNSSData & current_data, uint64_t current_timestamp); + +protected: + sl::GNSSData getNextGNSSValue(uint64_t current_timestamp); + +private: + unsigned _current_gnss_idx = 0; + unsigned long long _previous_ts = 0; + unsigned long long _last_cam_ts = 0; + nlohmann::json _gnss_data; + + std::shared_ptr _zed; +}; + +} // namespace sl_tools + +#endif diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_logging.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_logging.hpp new file mode 100644 index 0000000000..ad6cb6fa15 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_logging.hpp @@ -0,0 +1,210 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SL_LOGGING_HPP +#define SL_LOGGING_HPP + +#include + +// ----> DEBUG MACROS +// Common +#define DEBUG_COMM(...) \ + if (_debugCommon) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_COMM(stream_arg) \ + if (_debugCommon) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_COMM_ONCE(stream_arg) \ + if (_debugCommon) RCLCPP_DEBUG_STREAM_ONCE(get_logger(), stream_arg) + +// Dynamic parameters +#define DEBUG_DYN_PARAMS(...) \ + if (_debugDynParams) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_DYN_PARAMS(stream_arg) \ + if (_debugDynParams) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_DYN_PARAMS_ONCE(stream_arg) \ + if (_debugDynParams) RCLCPP_DEBUG_STREAM_ONCE(get_logger(), stream_arg) + +// Grab (low level) +#define DEBUG_GRAB(...) \ + if (_debugGrab) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_GRAB(stream_arg) \ + if (_debugGrab) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_GRAB_ONCE(stream_arg) \ + if (_debugGrab) RCLCPP_DEBUG_STREAM_ONCE(get_logger(), stream_arg) + +// Simulation +#define DEBUG_SIM(...) \ + if (_debugSim) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_ONCE_SIM(...) \ + if (_debugSim) RCLCPP_DEBUG_ONCE(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_SIM(stream_arg) \ + if (_debugSim) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_SIM(duration, stream_arg) \ + if (_debugSim) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } + +// Advanced +#define DEBUG_ADV(...) \ + if (_debugAdvanced) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_ONCE_ADV(...) \ + if (_debugAdvanced) RCLCPP_DEBUG_ONCE(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_ADV(stream_arg) \ + if (_debugAdvanced) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_ADV(duration, stream_arg) \ + if (_debugAdvanced) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } + +// Video Depth +#define DEBUG_VD(...) \ + if (_debugVideoDepth) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_VD(stream_arg) \ + if (_debugVideoDepth) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) + +// Camera Controls settings +#define DEBUG_CTRL(...) \ + if (_debugCamCtrl) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_CTRL(stream_arg) \ + if (_debugCamCtrl) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) + +// Point Cloud +#define DEBUG_PC(...) \ + if (_debugPointCloud) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_PC(stream_arg) \ + if (_debugPointCloud) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) + +// TF +#define DEBUG_TF(...) \ + if (_debugTf) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_ONCE_TF(...) \ + if (_debugTf) RCLCPP_DEBUG_ONCE(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_TF(stream_arg) \ + if (_debugTf) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_TF(duration, stream_arg) \ + if (_debugTf) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } + +// Positional Tracking +#define DEBUG_PT(...) \ + if (_debugPosTracking) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_ONCE_PT(...) \ + if (_debugPosTracking) RCLCPP_DEBUG_ONCE(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_PT(stream_arg) \ + if (_debugPosTracking) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_PT(duration, stream_arg) \ + if (_debugPosTracking) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } + +// GNSS integration +#define DEBUG_GNSS(...) \ + if (_debugGnss) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_GNSS(stream_arg) \ + if (_debugGnss) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_GNSS(duration, stream_arg) \ + if (_debugGnss) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } + +// Sensors +#define DEBUG_SENS(...) \ + if (_debugSensors) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_SENS(stream_arg) \ + if (_debugSensors) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_ONCE_SENS(stream_arg) \ + if (_debugSensors) RCLCPP_DEBUG_STREAM_ONCE(get_logger(), stream_arg) + +// Mapping +#define DEBUG_MAP(...) \ + if (_debugMapping) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_MAP(stream_arg) \ + if (_debugMapping) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_ONCE_MAP(stream_arg) \ + if (_debugMapping) RCLCPP_DEBUG_STREAM_ONCE(get_logger(), stream_arg) + +// Object Detection +#define DEBUG_OD(...) \ + if (_debugObjectDet) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_OD(stream_arg) \ + if (_debugObjectDet) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) + +// Body Tracking +#define DEBUG_BT(...) \ + if (_debugBodyTrk) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_BT(stream_arg) \ + if (_debugBodyTrk) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) + +// Region of Interest +#define DEBUG_ROI(...) \ + if (_debugRoi) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_ONCE_ROI(...) \ + if (_debugRoi) RCLCPP_DEBUG_ONCE(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_ROI(stream_arg) \ + if (_debugRoi) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_ROI(duration, stream_arg) \ + if (_debugRoi) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } + +// Streaming +#define DEBUG_STR(...) \ + if (_debugStreaming) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_ONCE_STR(...) \ + if (_debugStreaming) RCLCPP_DEBUG_ONCE(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_STR(stream_arg) \ + if (_debugStreaming) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_STR(duration, stream_arg) \ + if (_debugStreaming) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } + +// Nitros +#define DEBUG_NITROS(...) \ + if (_debugNitros) RCLCPP_DEBUG(get_logger(), __VA_ARGS__) +#define DEBUG_ONCE_NITROS(...) \ + if (_debugNitros) RCLCPP_DEBUG_ONCE(get_logger(), __VA_ARGS__) +#define DEBUG_STREAM_NITROS(stream_arg) \ + if (_debugNitros) RCLCPP_DEBUG_STREAM(get_logger(), stream_arg) +#define DEBUG_STREAM_THROTTLE_NITROS(duration, stream_arg) \ + if (_debugNitros) { \ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); \ + RCLCPP_DEBUG_STREAM_THROTTLE( \ + get_logger(), steady_clock, duration, \ + stream_arg); \ + } +// <---- DEBUG MACROS + +#endif // SL_LOGGING_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_tools.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_tools.hpp new file mode 100644 index 0000000000..f5ddc834e9 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_tools.hpp @@ -0,0 +1,405 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SL_TOOLS_HPP_ +#define SL_TOOLS_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gnss_replay.hpp" +#include "sl_win_avg.hpp" + +#include + +// Used to enable ZED SDK RealTime SVO pause +//#define USE_SVO_REALTIME_PAUSE + +// Used to enable Positional Tracking lock check +//#define ENABLE_PT_LOCK_CHECK + +// CUDA includes and macros +#ifdef FOUND_ISAAC_ROS_NITROS + #include "isaac_ros_nitros_image_type/nitros_image_builder.hpp" + + #define CUDA_CHECK(status) \ + if (status != cudaSuccess) \ + { \ + RCLCPP_ERROR_STREAM( \ + get_logger(), "Internal CUDA ERROR encountered: {" << std::string( \ + cudaGetErrorName( \ + status)) << "} {" << std::string(cudaGetErrorString(status)) << "}"); \ + std::abort(); \ + } +#endif + +namespace sl_tools +{ + +/*! \brief Get a parameter from the node + * \param node : the node to get the parameter from + * \param paramName : the name of the parameter + * \param defValue : the default value of the parameter + * \param outVal : the output value of the parameter + * \param log_info : the info to log + * \param dynamic : if the parameter is dynamic + * \param min : the minimum value of the parameter + * \param max : the maximum value of the parameter + * \tparam T : the type of the parameter + */ +template +void getParam( + const std::shared_ptr node, + std::string paramName, T defValue, T & outVal, + std::string log_info = std::string(), bool dynamic = false, + T minVal = std::numeric_limits::min(), T maxVal = std::numeric_limits::max()); + +/*! \brief Convert a sl::float3 to a vector of float + * \param r : the sl::float3 to convert + * \return a vector of float + */ +std::vector convertRodrigues(sl::float3 r); + +/*! + * @brief Get the full file path from a relative file name + * @param file_name the relative file name + * @return the full file path + */ +std::string getFullFilePath(const std::string & file_name); + +/*! \brief Get Stereolabs SDK version + * \param major : major value for version + * \param minor : minor value for version + * \param sub_minor _ sub_minor value for version + */ +std::string getSDKVersion(int & major, int & minor, int & sub_minor); + +/*! \brief Convert StereoLabs timestamp to ROS timestamp + * \param t : Stereolabs timestamp to be converted + * \param t : ROS 2 clock type + */ +rclcpp::Time slTime2Ros(sl::Timestamp t, rcl_clock_type_t clock_type = RCL_ROS_TIME); + +/*! \brief check if ZED + * \param camModel the model to check + */ +bool isZED(sl::MODEL camModel); + +/*! \brief check if ZED Mini + * \param camModel the model to check + */ +bool isZEDM(sl::MODEL camModel); + +/*! \brief check if ZED2 or ZED2i + * \param camModel the model to check + */ +bool isZED2OrZED2i(sl::MODEL camModel); + +/*! \brief check if ZED-X or ZED-X Mini + * \param camModel the model to check + */ +bool isZEDX(sl::MODEL camModel); + +/*! \brief check if Object Detection is available + * \param camModel the camera model to check + */ +bool isObjDetAvailable(sl::MODEL camModel); + +/*! \brief sl::Mat to ros message conversion + * \param img : the image to publish + * \param frameId : the id of the reference frame of the image + * \param t : rclcpp ros::Time to stamp the image + * \param use_pub_timestamp : if true use the current time as timestamp instead of \ref t + */ +std::unique_ptr imageToROSmsg( + const sl::Mat & img, const std::string & frameId, const rclcpp::Time & t, bool use_pub_timestamp); + +/*! \brief sl::Mat to ros message conversion + * \param left : the left image to convert and stitch + * \param right : the right image to convert and stitch + * \param frameId : the id of the reference frame of the image + * \param t : rclcpp rclcpp::Time to stamp the image + * \param use_pub_timestamp : if true use the current time as timestamp instead of \ref t + */ +std::unique_ptr imagesToROSmsg( + const sl::Mat & left, const sl::Mat & right, const std::string & frameId, + const rclcpp::Time & t, bool use_pub_timestamp); + +/*! \brief qos value to string + * \param qos the value to convert + */ +std::string qos2str(rmw_qos_history_policy_t qos); + +/*! \brief qos value to string + * \param qos the value to convert + */ +std::string qos2str(rmw_qos_reliability_policy_t qos); + +/*! \brief qos value to string + * \param qos the value to convert + */ +std::string qos2str(rmw_qos_durability_policy_t qos); + +/*! \brief Creates an sl::Mat containing a ROI from a polygon + * \param poly the ROI polygon. Coordinates must be normalized from 0.0 to 1.0 + * \param out_roi the `sl::Mat` containing the ROI + */ +bool generateROI(const std::vector & poly, sl::Mat & out_roi); + +/*! \brief Parse a vector of vector of floats from a string. + * \param input + * \param error_return + * Syntax is [[1.0, 2.0], [3.3, 4.4, 5.5], ...] */ +std::vector> parseStringMultiVector_float( + const std::string & input, std::string & error_return); + +/*! \brief Parse a vector of integer values from a string. + * \param input + * \param error_return + * Syntax is [1, 2, 3, ...] */ +std::vector parseStringVector_int( + const std::string & input, + std::string & error_return); + +/*! + * @brief Convert thread policy to string + * @param thread_sched_policy + * @return policy string + */ +std::string threadSched2Str(int thread_sched_policy); + +/*! + * @brief check if root is available + * @return true if root + */ +bool checkRoot(); + +/*! + * @brief Convert seconds to string in format DD:HH:MM:SS + * @param sec seconds + * @return string + */ +std::string seconds2str(double sec); + +/*! + * @brief read custom OD labels from a COCO-Like YAML file + * @param label_file label file full path + * @param out_labels the map containing the labels. The map idx corresponds to the class ID + * @return true if successfull + */ +bool ReadCocoYaml( + const std::string & label_file, std::unordered_map & out_labels); + +/** + * @brief Stop Timer used to measure time intervals + * + */ +class StopWatch +{ +public: + explicit StopWatch(rclcpp::Clock::SharedPtr clock); + ~StopWatch() {} + + void tic(); //!< Set the reference time point to the current time + double toc(std::string func_name = std::string() ); //!< Returns the seconds elapsed from the last tic in ROS clock reference (it works also in simulation) + +private: + rclcpp::Time mStartTime; // Reference time point + rclcpp::Clock::SharedPtr mClockPtr; // Node clock interface +}; + +// ----> Utility functions + +/*! \brief Convert a string to uppercase (ASCII) + * \param s : the string to convert + * \return the uppercase string + */ +inline std::string toUpper(std::string s) +{ + std::transform( + s.begin(), s.end(), s.begin(), + [](unsigned char c) {return std::toupper(c);}); + return s; +} + +// ----> Template functions definitions + +// Match a YAML string (with underscores) to an sl:: SDK enum value. +// Case-insensitive. Iterates from `first` up to (excluding) `last`, +// comparing sl::toString() output (spaces replaced by underscores). +// Returns true on match. +template +bool matchSdkEnum( + const std::string & str, EnumT first, EnumT last, EnumT & outVal) +{ + const std::string upperStr = toUpper(str); + + for (int idx = static_cast(first); + idx < static_cast(last); ++idx) + { + EnumT candidate = static_cast(idx); + std::string candidate_str = sl::toString(candidate).c_str(); + std::replace(candidate_str.begin(), candidate_str.end(), ' ', '_'); + if (upperStr == toUpper(candidate_str)) { + outVal = candidate; + return true; + } + } + return false; +} + +/*! \brief Read a ROS parameter and match it to an SDK enum value. + * Combines getParam + matchSdkEnum + warning on mismatch + info log. + * \param node : the node to get the parameter from + * \param paramName : the ROS parameter name + * \param defaultStr : the default string value for the parameter + * \param first : first enum value to iterate from + * \param last : sentinel (exclusive) enum value + * \param outVal : receives the matched enum value (unchanged on mismatch) + * \param logLabel : label prefix for the INFO log (empty to skip logging) + * \return true if the parameter matched a valid enum value + */ +template +bool getEnumParam( + const std::shared_ptr node, + const std::string & paramName, + const std::string & defaultStr, + EnumT first, EnumT last, + EnumT & outVal, + const std::string & logLabel = std::string()) +{ + std::string str = defaultStr; + getParam(node, paramName, str, str); + bool ok = matchSdkEnum(str, first, last, outVal); + if (!ok) { + RCLCPP_WARN_STREAM( + node->get_logger(), + "The value of the parameter '" << paramName << "' is not valid: '" + << str << "'. Using the default value."); + } + if (!logLabel.empty()) { + RCLCPP_INFO_STREAM( + node->get_logger(), + logLabel << sl::toString(outVal).c_str()); + } + return ok; +} + +template +void getParam( + const std::shared_ptr node, + std::string paramName, T defValue, T & outVal, + std::string log_info, bool dynamic, + T minVal, T maxVal) +{ + rcl_interfaces::msg::ParameterDescriptor descriptor; + descriptor.read_only = !dynamic; + + std::stringstream ss; + if constexpr (std::is_same::value) { + ss << "Default value: " << (defValue ? "TRUE" : "FALSE"); + } else { + ss << "Default value: " << defValue; + } + descriptor.description = ss.str(); + + if constexpr (std::is_same::value) { + descriptor.additional_constraints = "Range: [" + std::to_string(minVal) + ", " + std::to_string( + maxVal) + "]"; + rcl_interfaces::msg::FloatingPointRange range; + range.from_value = minVal; + range.to_value = maxVal; + descriptor.floating_point_range.push_back(range); + } else if constexpr (std::is_same::value) { + descriptor.additional_constraints = "Range: [" + std::to_string(minVal) + ", " + std::to_string( + maxVal) + "]"; + rcl_interfaces::msg::IntegerRange range; + range.from_value = minVal; + range.to_value = maxVal; + descriptor.integer_range.push_back(range); + } + + node->declare_parameter(paramName, rclcpp::ParameterValue(defValue), descriptor); + + if (!node->get_parameter(paramName, outVal)) { + RCLCPP_WARN_STREAM( + node->get_logger(), + "The parameter '" + << paramName + << "' is not available or is not valid, using the default value: " + << defValue); + } + + if (!log_info.empty()) { + std::stringstream ss; + ss << log_info; + if constexpr (std::is_same::value) { + ss << (outVal ? "TRUE" : "FALSE"); + } else { + ss << outVal; + } + if (dynamic) { + ss << " [DYNAMIC]"; + } + RCLCPP_INFO_STREAM(node->get_logger(), ss.str()); + } +} +// Validate and assign a dynamic parameter within [minVal, maxVal]. +// Returns true on success. On failure, sets result.successful = false with reason. +template +bool checkParamRange( + const rclcpp::Parameter & param, + T & outVal, + T minVal, T maxVal, + rcl_interfaces::msg::SetParametersResult & result, + const rclcpp::Logger & logger) +{ + T val; + if constexpr (std::is_same_v) { + val = param.as_double(); + } else if constexpr (std::is_same_v) { + val = static_cast(param.as_double()); + } else if constexpr (std::is_same_v) { + val = param.as_int(); + } else { + static_assert( + std::is_same_v|| std::is_same_v|| std::is_same_v, + "checkParamRange only supports double, float and int"); + } + + if (val < minVal || val > maxVal) { + result.successful = false; + result.reason = param.get_name() + " must be in range [" + + std::to_string(minVal) + ", " + std::to_string(maxVal) + "]"; + RCLCPP_WARN_STREAM(logger, result.reason); + return false; + } + outVal = val; + return true; +} +// <---- Template functions definitions + +} // namespace sl_tools + +#endif // SL_TOOLS_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_types.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_types.hpp new file mode 100644 index 0000000000..83eacb5332 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_types.hpp @@ -0,0 +1,204 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SL_TYPES_HPP_ +#define SL_TYPES_HPP_ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef FOUND_ISAAC_ROS_NITROS + #include "isaac_ros_managed_nitros/managed_nitros_publisher.hpp" + #include "isaac_ros_nitros_image_type/nitros_image.hpp" +#endif + +#ifdef FOUND_POINT_CLOUD_TRANSPORT + #include +#endif + +#define TIMEZERO_ROS rclcpp::Time(0, 0, RCL_ROS_TIME) +#define TIMEZERO_SYS rclcpp::Time(0, 0, RCL_SYSTEM_TIME) + +constexpr auto HEARTBEAT_INTERVAL_MS = 1000; // Publish heartbeat every second +constexpr auto TEMP_PUB_INTERVAL_MS = 1000; // Publish temperature every second + +namespace stereolabs +{ + +// ----> Global constants +const double DEG2RAD = 0.017453293; +const double RAD2DEG = 57.295777937; + +const sl::COORDINATE_SYSTEM ROS_COORDINATE_SYSTEM = + sl::COORDINATE_SYSTEM::RIGHT_HANDED_Z_UP_X_FWD; +const sl::UNIT ROS_MEAS_UNITS = sl::UNIT::METER; + +const int QOS_QUEUE_SIZE = 10; +// <---- Global constants + +#ifdef _SL_JETSON_ +const bool IS_JETSON = true; +#else +const bool IS_JETSON = false; +#endif + +const float NOT_VALID_TEMP = -273.15f; + +// ----> Typedefs to simplify declarations + +#ifdef FOUND_ISAAC_ROS_NITROS +typedef std::shared_ptr> nitrosImgPub; +#endif + +typedef std::shared_ptr camInfoMsgPtr; + +typedef rclcpp::Publisher::SharedPtr camInfoPub; +typedef rclcpp::Publisher::SharedPtr clockPub; +typedef rclcpp::Publisher::SharedPtr svoStatusPub; +typedef rclcpp::Publisher::SharedPtr healthStatusPub; +typedef rclcpp::Publisher::SharedPtr heartbeatStatusPub; + +typedef rclcpp::Publisher::SharedPtr imagePub; +typedef rclcpp::Publisher::SharedPtr disparityPub; + +typedef rclcpp::Publisher::SharedPtr pointcloudPub; + +typedef rclcpp::Publisher::SharedPtr imuPub; +typedef rclcpp::Publisher::SharedPtr magPub; +typedef rclcpp::Publisher::SharedPtr pressPub; +typedef rclcpp::Publisher::SharedPtr tempPub; + +typedef rclcpp::Publisher::SharedPtr posePub; +typedef rclcpp::Publisher::SharedPtr poseStatusPub; +typedef rclcpp::Publisher::SharedPtr gnssFusionStatusPub; +typedef rclcpp::Publisher::SharedPtr poseCovPub; +typedef rclcpp::Publisher::SharedPtr transfPub; +typedef rclcpp::Publisher::SharedPtr odomPub; +typedef rclcpp::Publisher::SharedPtr pathPub; + +typedef rclcpp::Publisher::SharedPtr objPub; +typedef rclcpp::Publisher::SharedPtr depthInfoPub; + +typedef rclcpp::Publisher::SharedPtr planePub; +typedef rclcpp::Publisher::SharedPtr markerPub; + +typedef rclcpp::Publisher::SharedPtr geoPosePub; +typedef rclcpp::Publisher::SharedPtr gnssFixPub; + +typedef rclcpp::Publisher::SharedPtr healthPub; + +typedef rclcpp::Subscription::SharedPtr clickedPtSub; +typedef rclcpp::Subscription::SharedPtr gnssFixSub; +typedef rclcpp::Subscription::SharedPtr clockSub; + +typedef rclcpp::Service::SharedPtr enableDepthPtr; + +typedef rclcpp::Service::SharedPtr resetOdomSrvPtr; +typedef rclcpp::Service::SharedPtr resetPosTrkSrvPtr; +typedef rclcpp::Service::SharedPtr setPoseSrvPtr; +typedef rclcpp::Service::SharedPtr saveAreaMemorySrvPtr; +typedef rclcpp::Service::SharedPtr enableObjDetPtr; +typedef rclcpp::Service::SharedPtr enableBodyTrkPtr; +typedef rclcpp::Service::SharedPtr enableMappingPtr; + +typedef rclcpp::Service::SharedPtr startSvoRecSrvPtr; +typedef rclcpp::Service::SharedPtr setRoiSrvPtr; +typedef rclcpp::Service::SharedPtr stopSvoRecSrvPtr; +typedef rclcpp::Service::SharedPtr pauseSvoSrvPtr; +typedef rclcpp::Service::SharedPtr setSvoFramePtr; +typedef rclcpp::Service::SharedPtr resetRoiSrvPtr; +typedef rclcpp::Service::SharedPtr toLLSrvPtr; +typedef rclcpp::Service::SharedPtr fromLLSrvPtr; +typedef rclcpp::Service::SharedPtr enableStreamingPtr; + + +/*! + * @brief Video/Depth topic resolution + */ +typedef enum +{ + NATIVE, //!< Same camera grab resolution + CUSTOM //!< Custom Rescale Factor +} PubRes; + +std::string toString(const PubRes & res); + +typedef enum +{ + PUB, //!< Same resolution as Color and Depth Map. [Old behavior for compatibility] + FULL, //!< Full resolution. Not recommended because slow processing and high bandwidth requirements + COMPACT, //!< Standard resolution. Optimizes processing and bandwidth + REDUCED //!< Half resolution. Low processing and bandwidth requirements +} PcRes; + +std::string toString(const PcRes & res); + +const int NEURAL_W = 896; +const int NEURAL_H = 512; +// <---- Typedefs to simplify declarations + +} // namespace stereolabs + +#endif // SL_TYPES_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_win_avg.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_win_avg.hpp new file mode 100644 index 0000000000..8a9bf66720 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/include/sl_win_avg.hpp @@ -0,0 +1,51 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SL_WIN_AVG_HPP_ +#define SL_WIN_AVG_HPP_ + +#include // size_t +#include // std::dequeue +#include + +namespace sl_tools +{ + +class WinAvg +{ +public: + explicit WinAvg(size_t win_size = 15); + ~WinAvg(); + + double setNewSize(size_t win_size); + double addValue(double val); + + /// @brief Get the current average of the stored values + /// @return average of the stored values + double getAvg(); + + inline size_t size() {return mVals.size();} + +private: + size_t mWinSize; + + std::deque mVals; // The values in the queue used to calculate the windowed average + double mSumVals = 0.0; // The updated sum of the values in the queue + + std::mutex mQueueMux; +}; + +} + +#endif // SL_WIN_AVG_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/gnss_replay.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/gnss_replay.cpp new file mode 100644 index 0000000000..f058d784ae --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/gnss_replay.cpp @@ -0,0 +1,328 @@ +#include "gnss_replay.hpp" + +using json = nlohmann::json; + +namespace sl_tools +{ + +inline bool is_microseconds(uint64_t timestamp) +{ + // Check if the timestamp is in microseconds + return 1'000'000'000'000'000 <= timestamp && timestamp < 10'000'000'000'000'000ULL; +} + +inline bool is_nanoseconds(uint64_t timestamp) +{ + // Check if the timestamp is in microseconds + return 1'000'000'000'000'000'000 <= timestamp && timestamp < 10'000'000'000'000'000'000ULL; +} + +GNSSReplay::GNSSReplay(const std::shared_ptr & zed) {_zed = zed;} + +GNSSReplay::~GNSSReplay() {close();} + +bool GNSSReplay::initialize() +{ + auto svo_custom_data_keys = _zed->getSVODataKeys(); + std::string gnss_key = "GNSS_json"; + bool found = false; + for (auto & it : svo_custom_data_keys) { + if (it.find(gnss_key) != std::string::npos) { + found = true; + break; + } + } + + if (!found) { + return false; + } + + std::map data; + auto status = _zed->retrieveSVOData(gnss_key, data); // Get ALL + + /* + We handle 2 formats: + * + * { + "coordinates": { + "latitude": XXX, + "longitude": XXX, + "altitude": XXX + }, + "ts": 1694263390000000, + "latitude_std": 0.51, + "longitude_std": 0.51, + "altitude_std": 0.73, + "position_covariance": [ + 0.2601, + 0, + 0, + 0, + 0.2601, + 0, + 0, + 0, + 0.5328999999999999 + ] + }, + ========= + * Or + * this one will be converted to the format above + { + "Eph": 0.467, + "EpochTimeStamp": 1694266998000000, + "Epv": 0.776, + "Geopoint": { + "Altitude": XXX, + "Latitude": XXX, + "Longitude": XXX + }, + "Position": [ + [ + XXX, + XXX, + XXX + ] + ], + "Velocity": [ + [ + -0.63, + 0.25, + 0.53 + ] + ] + } + */ + + auto tmp_array = json::array(); + for (auto & it : data) { + try { + auto _gnss_data_point = + json::parse(it.second.content.begin(), it.second.content.end()); + auto _gnss_data_point_formatted = json::object(); + + if (!_gnss_data_point["Geopoint"].is_null()) { + _gnss_data_point_formatted["coordinates"] = { + {"latitude", _gnss_data_point["Geopoint"]["Latitude"]}, + {"longitude", _gnss_data_point["Geopoint"]["Longitude"]}, + {"altitude", _gnss_data_point["Geopoint"]["Altitude"]}, + }; + _gnss_data_point_formatted["ts"] = _gnss_data_point["EpochTimeStamp"]; + + float latitude_std = _gnss_data_point["Eph"]; + float longitude_std = _gnss_data_point["Eph"]; + float altitude_std = _gnss_data_point["Epv"]; + + _gnss_data_point_formatted["latitude_std"] = latitude_std; + _gnss_data_point_formatted["longitude_std"] = longitude_std; + _gnss_data_point_formatted["altitude_std"] = altitude_std; + + _gnss_data_point_formatted["position_covariance"] = + json::array( + {longitude_std + longitude_std, 0, 0, 0, + latitude_std + latitude_std, 0, 0, 0, + altitude_std + altitude_std}); + + _gnss_data_point_formatted["original__gnss_data"] = _gnss_data_point; + + } else if (!_gnss_data_point["coordinates"].is_null() && + !_gnss_data_point["latitude_std"].is_null() && + !_gnss_data_point["longitude_std"].is_null()) + { + // no conversion + _gnss_data_point_formatted = _gnss_data_point; + } + + tmp_array.push_back(_gnss_data_point_formatted); + + } catch (const std::runtime_error & e) { + std::cerr << "Error while reading GNSS data: " << e.what() << std::endl; + } + } + _gnss_data["GNSS"] = tmp_array; + + _current_gnss_idx = 0; + _previous_ts = 0; + + return true; +} + +void GNSSReplay::close() +{ + _gnss_data.clear(); + _current_gnss_idx = 0; +} + + +inline std::string gps_mode2str(int status) +{ + std::string out; + switch (status) { + case 1: + out = "STATUS_GPS"; + break; + case 2: + out = "STATUS_DGPS"; + break; + case 3: + out = "STATUS_RTK_FIX"; + break; + case 4: + out = "STATUS_RTK_FLT"; + break; + case 5: + out = "STATUS_DR"; + break; + case 6: + out = "STATUS_GNSSDR"; + break; + case 7: + out = "STATUS_TIME"; + break; + case 8: + out = "STATUS_SIM"; + break; + case 9: + out = "STATUS_PPS_FIX"; + break; + default: + case 0: + out = "STATUS_UNK"; + break; + } + return out; +} + +sl::GNSSData getGNSSData(json & _gnss_data, int gnss_idx) +{ + sl::GNSSData current__gnss_data; + current__gnss_data.ts = 0; + + // If we are at the end of GNSS data, exit + if (gnss_idx >= _gnss_data["GNSS"].size()) { + std::cout << "Reached the end of the GNSS playback data." << std::endl; + return current__gnss_data; + } + + json current__gnss_data_json = _gnss_data["GNSS"][gnss_idx]; + // Check inputs: + if ( + current__gnss_data_json["coordinates"].is_null() || + current__gnss_data_json["coordinates"]["latitude"].is_null() || + current__gnss_data_json["coordinates"]["longitude"].is_null() || + current__gnss_data_json["coordinates"]["altitude"].is_null() || + current__gnss_data_json["ts"].is_null()) + { + std::cout << "Null GNSS playback data." << std::endl; + return current__gnss_data; + } + + + // if (!current__gnss_data_json["original__gnss_data"].is_null()) { + // if (!current__gnss_data_json["original__gnss_data"]["fix"].is_null()) { + // if (!current__gnss_data_json["original__gnss_data"]["fix"]["status"].is_null()) + // std::cout << "GNSS info: " << gps_mode2str(current__gnss_data_json["original__gnss_data"]["fix"]["status"]) << " " << current__gnss_data_json["longitude_std"] << " " << current__gnss_data_json["altitude_std"] << std::endl; + // } + // } + + auto gnss_timestamp = current__gnss_data_json["ts"].get(); + // Fill out timestamp: + if (is_microseconds(gnss_timestamp)) { + current__gnss_data.ts.setMicroseconds(gnss_timestamp); + } else if (is_nanoseconds(gnss_timestamp)) { + current__gnss_data.ts.setNanoseconds(gnss_timestamp); + } else { + std::cerr << "Warning: Invalid timestamp format from GNSS file" << std::endl; + } + + // Fill out coordinates: + current__gnss_data.setCoordinates( + current__gnss_data_json["coordinates"]["latitude"].get(), + current__gnss_data_json["coordinates"]["longitude"].get(), + current__gnss_data_json["coordinates"]["altitude"].get(), + false); + + // Fill out default standard deviation: + current__gnss_data.longitude_std = current__gnss_data_json["longitude_std"]; + current__gnss_data.latitude_std = current__gnss_data_json["latitude_std"]; + current__gnss_data.altitude_std = current__gnss_data_json["altitude_std"]; + // Fill out covariance [must be not null] + std::array position_covariance; + for (unsigned i = 0; i < 9; i++) { + position_covariance[i] = 0.0; // initialize empty covariance + + } + // set covariance diagonal + position_covariance[0] = current__gnss_data.longitude_std * current__gnss_data.longitude_std; + position_covariance[1 * 3 + 1] = current__gnss_data.latitude_std * + current__gnss_data.latitude_std; + position_covariance[2 * 3 + 2] = current__gnss_data.altitude_std * + current__gnss_data.altitude_std; + current__gnss_data.position_covariance = position_covariance; + + return current__gnss_data; +} + +sl::GNSSData GNSSReplay::getNextGNSSValue(uint64_t current_timestamp) +{ + sl::GNSSData current__gnss_data = getGNSSData(_gnss_data, _current_gnss_idx); + + if (current__gnss_data.ts.data_ns == 0) { + return current__gnss_data; + } + + if (current__gnss_data.ts.data_ns > current_timestamp) { + current__gnss_data.ts.data_ns = 0; + return current__gnss_data; + } + + sl::GNSSData last_data; + int step = 1; + while (1) { + last_data = current__gnss_data; + int64_t diff_last = + static_cast(current_timestamp) - + static_cast(current__gnss_data.ts.data_ns); + current__gnss_data = getGNSSData(_gnss_data, _current_gnss_idx + step++); + if (current__gnss_data.ts.data_ns == 0) { //error / end of file + break; + } + + if (current__gnss_data.ts.data_ns > current_timestamp) { + int64_t diff_current = + static_cast(current__gnss_data.ts.data_ns) - + static_cast(current_timestamp); + if (diff_current > diff_last) { // keep last + current__gnss_data = last_data; + } + break; + } + _current_gnss_idx++; + } + + return current__gnss_data; +} + +sl::FUSION_ERROR_CODE GNSSReplay::grab(sl::GNSSData & current_data, uint64_t current_timestamp) +{ + current_data.ts.data_ns = 0; + + if (current_timestamp > 0 && (current_timestamp > _last_cam_ts)) { + current_data = getNextGNSSValue(current_timestamp); + } + + if (current_data.ts.data_ns == _previous_ts) { + current_data.ts.data_ns = 0; + } + + _last_cam_ts = current_timestamp; + + if (current_data.ts.data_ns == 0) { // Invalid data + return sl::FUSION_ERROR_CODE::FAILURE; + } + + _previous_ts = current_data.ts.data_ns; + return sl::FUSION_ERROR_CODE::SUCCESS; +} + +} // namespace sl_tools diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_tools.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_tools.cpp new file mode 100644 index 0000000000..c287438258 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_tools.cpp @@ -0,0 +1,731 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include // getuid + +#include +#include +#include + +#include +#include + +#include "sl_tools.hpp" + +namespace sl_tools +{ +std::vector convertRodrigues(sl::float3 r) +{ + float theta = sqrt(r.x * r.x + r.y * r.y + r.z * r.z); + + std::vector R = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if (theta < FLT_EPSILON) { + return R; + } else { + float c = cos(theta); + float s = sin(theta); + float c1 = 1.f - c; + float itheta = theta ? 1.f / theta : 0.f; + + r *= itheta; + + std::vector rrt = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + float * p = rrt.data(); + p[0] = r.x * r.x; + p[1] = r.x * r.y; + p[2] = r.x * r.z; + p[3] = r.x * r.y; + p[4] = r.y * r.y; + p[5] = r.y * r.z; + p[6] = r.x * r.z; + p[7] = r.y * r.z; + p[8] = r.z * r.z; + + std::vector r_x = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + p = r_x.data(); + p[0] = 0; + p[1] = -r.z; + p[2] = r.y; + p[3] = r.z; + p[4] = 0; + p[5] = -r.x; + p[6] = -r.y; + p[7] = r.x; + p[8] = 0; + + // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x] + + sl::Matrix3f eye; + eye.setIdentity(); + + sl::Matrix3f sl_R(R.data()); + sl::Matrix3f sl_rrt(rrt.data()); + sl::Matrix3f sl_r_x(r_x.data()); + + sl_R = eye * c + sl_rrt * c1 + sl_r_x * s; + + R[0] = sl_R.r00; + R[1] = sl_R.r01; + R[2] = sl_R.r02; + R[3] = sl_R.r10; + R[4] = sl_R.r11; + R[5] = sl_R.r12; + R[6] = sl_R.r20; + R[7] = sl_R.r21; + R[8] = sl_R.r22; + } + + return R; +} + +std::string getFullFilePath(const std::string & file_name) +{ + std::string new_filename; + if (file_name.front() == '~') { + const char * home_env = std::getenv("HOME"); + std::string home_path = home_env ? home_env : "/tmp"; + if (!home_path.empty()) { + new_filename = home_path; + new_filename += file_name.substr(1, file_name.size() - 1); + } + } else { + new_filename = file_name; + } + + std::filesystem::path path(new_filename); + auto abs_path = std::filesystem::absolute(path); + return abs_path.string(); +} + +std::string getSDKVersion(int & major, int & minor, int & sub_minor) +{ + std::string ver = sl::Camera::getSDKVersion().c_str(); + std::vector strings; + std::istringstream f(ver); + std::string s; + + while (getline(f, s, '.')) { + strings.push_back(s); + } + + major = 0; + minor = 0; + sub_minor = 0; + + switch (strings.size()) { + case 3: + sub_minor = std::stoi(strings[2]); + + case 2: + minor = std::stoi(strings[1]); + + case 1: + major = std::stoi(strings[0]); + } + + return ver; +} + +rclcpp::Time slTime2Ros(sl::Timestamp t, rcl_clock_type_t clock_type) +{ + uint64_t ts_nsec = t.getNanoseconds(); + uint32_t sec = static_cast(ts_nsec / 1000000000); + uint32_t nsec = static_cast(ts_nsec % 1000000000); + return rclcpp::Time(sec, nsec, clock_type); +} + +std::unique_ptr imageToROSmsg( + const sl::Mat & img, const std::string & frameId, const rclcpp::Time & t, bool use_pub_timestamp) +{ + std::unique_ptr imgMessage = std::make_unique(); + + imgMessage->header.stamp = use_pub_timestamp ? rclcpp::Clock().now() : t; + imgMessage->header.frame_id = frameId; + imgMessage->height = img.getHeight(); + imgMessage->width = img.getWidth(); + + int num = 1; // for endianness detection + imgMessage->is_bigendian = !(*reinterpret_cast(&num) == 1); + + imgMessage->step = img.getStepBytes(); + + size_t size = imgMessage->step * imgMessage->height; + + uint8_t * data_ptr = nullptr; + + sl::MAT_TYPE dataType = img.getDataType(); + + switch (dataType) { + case sl::MAT_TYPE::F32_C1: /**< float 1 channel.*/ + imgMessage->encoding = sensor_msgs::image_encodings::TYPE_32FC1; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + case sl::MAT_TYPE::F32_C2: /**< float 2 channels.*/ + imgMessage->encoding = sensor_msgs::image_encodings::TYPE_32FC2; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + case sl::MAT_TYPE::F32_C3: /**< float 3 channels.*/ + imgMessage->encoding = sensor_msgs::image_encodings::TYPE_32FC3; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + case sl::MAT_TYPE::F32_C4: /**< float 4 channels.*/ + imgMessage->encoding = sensor_msgs::image_encodings::TYPE_32FC4; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + case sl::MAT_TYPE::U8_C1: /**< unsigned char 1 channel.*/ + imgMessage->encoding = sensor_msgs::image_encodings::MONO8; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + case sl::MAT_TYPE::U8_C2: /**< unsigned char 2 channels.*/ + imgMessage->encoding = sensor_msgs::image_encodings::TYPE_8UC2; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + case sl::MAT_TYPE::U8_C3: /**< unsigned char 3 channels.*/ + imgMessage->encoding = sensor_msgs::image_encodings::BGR8; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + case sl::MAT_TYPE::U8_C4: /**< unsigned char 4 channels.*/ + imgMessage->encoding = sensor_msgs::image_encodings::BGRA8; + data_ptr = reinterpret_cast(img.getPtr()); + break; + + default: + RCLCPP_ERROR( + rclcpp::get_logger("sl_tools"), + "imageToROSmsg: unsupported MAT_TYPE %d", static_cast(dataType)); + return imgMessage; + } + + if (data_ptr == nullptr) { + RCLCPP_ERROR( + rclcpp::get_logger("sl_tools"), + "imageToROSmsg: getPtr returned nullptr (GPU-only or unallocated Mat)"); + return imgMessage; + } + + imgMessage->data = std::vector(data_ptr, data_ptr + size); + + return imgMessage; +} + +std::unique_ptr imagesToROSmsg( + const sl::Mat & left, const sl::Mat & right, const std::string & frameId, + const rclcpp::Time & t, bool use_pub_timestamp) +{ + std::unique_ptr imgMsgPtr = std::make_unique(); + + if ( + left.getWidth() != right.getWidth() || left.getHeight() != right.getHeight() || + left.getChannels() != right.getChannels() || left.getDataType() != right.getDataType()) + { + return imgMsgPtr; + } + + imgMsgPtr->header.stamp = use_pub_timestamp ? rclcpp::Clock().now() : t; + imgMsgPtr->header.frame_id = frameId; + imgMsgPtr->height = left.getHeight(); + imgMsgPtr->width = 2 * left.getWidth(); + + int num = 1; // for endianness detection + imgMsgPtr->is_bigendian = !(*reinterpret_cast(&num) == 1); + + imgMsgPtr->step = 2 * left.getStepBytes(); + + size_t size = imgMsgPtr->step * imgMsgPtr->height; + imgMsgPtr->data.resize(size); + + sl::MAT_TYPE dataType = left.getDataType(); + + char * srcL; + char * srcR; + + switch (dataType) { + case sl::MAT_TYPE::F32_C1: /**< float 1 channel.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::TYPE_32FC1; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + case sl::MAT_TYPE::F32_C2: /**< float 2 channels.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::TYPE_32FC2; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + case sl::MAT_TYPE::F32_C3: /**< float 3 channels.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::TYPE_32FC3; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + case sl::MAT_TYPE::F32_C4: /**< float 4 channels.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::TYPE_32FC4; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + case sl::MAT_TYPE::U8_C1: /**< unsigned char 1 channel.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::MONO8; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + case sl::MAT_TYPE::U8_C2: /**< unsigned char 2 channels.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::TYPE_8UC2; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + case sl::MAT_TYPE::U8_C3: /**< unsigned char 3 channels.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::BGR8; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + case sl::MAT_TYPE::U8_C4: /**< unsigned char 4 channels.*/ + imgMsgPtr->encoding = sensor_msgs::image_encodings::BGRA8; + srcL = reinterpret_cast(left.getPtr()); + srcR = reinterpret_cast(right.getPtr()); + break; + + default: + RCLCPP_ERROR( + rclcpp::get_logger("sl_tools"), + "imagesToROSmsg: unsupported MAT_TYPE %d", static_cast(dataType)); + return imgMsgPtr; + } + + if (srcL == nullptr || srcR == nullptr) { + RCLCPP_ERROR( + rclcpp::get_logger("sl_tools"), + "imagesToROSmsg: getPtr returned nullptr (GPU-only or unallocated Mat)"); + return imgMsgPtr; + } + + char * dest = reinterpret_cast((&imgMsgPtr->data[0])); + + for (int i = 0; i < left.getHeight(); i++) { + memcpy(dest, srcL, left.getStepBytes()); + dest += left.getStepBytes(); + memcpy(dest, srcR, right.getStepBytes()); + dest += right.getStepBytes(); + + srcL += left.getStepBytes(); + srcR += right.getStepBytes(); + } + + return imgMsgPtr; +} + +std::string qos2str(rmw_qos_history_policy_t qos) +{ + if (qos == RMW_QOS_POLICY_HISTORY_KEEP_LAST) { + return "KEEP_LAST"; + } + + if (qos == RMW_QOS_POLICY_HISTORY_KEEP_ALL) { + return "KEEP_ALL"; + } + + return "Unknown QoS value"; +} + +std::string qos2str(rmw_qos_reliability_policy_t qos) +{ + if (qos == RMW_QOS_POLICY_RELIABILITY_RELIABLE) { + return "RELIABLE"; + } + + if (qos == RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT) { + return "BEST_EFFORT"; + } + + return "Unknown QoS value"; +} + +std::string qos2str(rmw_qos_durability_policy_t qos) +{ + if (qos == RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL) { + return "TRANSIENT_LOCAL"; + } + + if (qos == RMW_QOS_POLICY_DURABILITY_VOLATILE) { + return "VOLATILE"; + } + + return "Unknown QoS value"; +} + +inline bool contains(const std::vector & poly, sl::float2 test) +{ + int i, j; + bool c = false; + const int nvert = poly.size(); + for (i = 0, j = nvert - 1; i < nvert; j = i++) { + if ( + ((poly[i].y > test.y) != (poly[j].y > test.y)) && + (test.x < + (poly[j].x - poly[i].x) * (test.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)) + { + c = !c; + } + } + return c; +} + +bool generateROI(const std::vector & poly, sl::Mat & out_roi) +{ + if (poly.size() < 3) { + out_roi = sl::Mat(); + return false; + } + + // Set each pixel to valid + //std::cerr << "Setting ROI mask to full valid" << std::endl; + out_roi.setTo(255, sl::MEM::CPU); + + // ----> De-normalize coordinates + size_t w = out_roi.getWidth(); + size_t h = out_roi.getHeight(); + + //std::cerr << "De-normalize coordinates" << std::endl; + //std::cerr << "Image resolution: " << w << "x" << h << std::endl; + //std::cerr << "Polygon size: " << poly.size() << std::endl; + std::vector poly_img; + size_t idx = 0; + for (auto & it : poly) { + sl::float2 pt; + pt.x = it.x * w; + pt.y = it.y * h; + + if (pt.x >= w) { + pt.x = (w - 1); + } + if (pt.y >= h) { + pt.y = (h - 1); + } + + poly_img.push_back(pt); + + //std::cerr << "Pushed pt #: " << idx << std::endl; + ++idx; + } + // <---- De-normalize coordinates + + // ----> Unset ROI pixels outside the polygon + //std::cerr << "Unset ROI pixels outside the polygon" << std::endl; + //std::cerr << "Set mask" << std::endl; + for (int v = 0; v < h; v++) { + for (int u = 0; u < w; u++) { + if (!contains(poly_img, sl::float2(u, v))) { + out_roi.setValue(u, v, 0, sl::MEM::CPU); + } + } + } + //std::cerr << "Mask ready" << std::endl; + //std::cerr << "ROI resolution: " << w << "x" << h << std::endl; + // <---- Unset ROI pixels outside the polygon + + return true; +} + +std::vector parseStringVector_int( + const std::string & input, + std::string & error_return) +{ + std::vector result; + + if (input == "[]") { + error_return = ""; + return result; + } + + if (input.empty() || input.front() != '[' || input.back() != ']') { + error_return = "Vector string must start with [ and end with ]"; + return result; + } + + std::string trimmed = input; + trimmed.erase( + std::remove(trimmed.begin(), trimmed.end(), '['), + trimmed.end()); + trimmed.erase( + std::remove(trimmed.begin(), trimmed.end(), ']'), + trimmed.end()); + + std::stringstream ss(trimmed); + std::string token; + while (std::getline(ss, token, ',')) { + // Trim leading and trailing whitespace + token.erase(0, token.find_first_not_of(" \t\n\r")); + token.erase(token.find_last_not_of(" \t\n\r") + 1); + + if (token.empty()) { + continue; + } + + try { + int value = std::stoi(token); + result.push_back(value); + } catch (const std::exception & e) { + error_return = "Failed to parse integer: " + token; + return result; + } + } + error_return = ""; + return result; +} + +std::vector> parseStringMultiVector_float( + const std::string & input, std::string & error_return) +{ + std::vector> result; + + std::stringstream input_ss(input); + int depth = 0; + std::vector current_vector; + while (!!input_ss && !input_ss.eof()) { + switch (input_ss.peek()) { + case EOF: + break; + case '[': + depth++; + if (depth > 2) { + error_return = "Array depth greater than 2"; + return result; + } + input_ss.get(); + current_vector.clear(); + break; + case ']': + depth--; + if (depth < 0) { + error_return = "More close ] than open ["; + return result; + } + input_ss.get(); + if (depth == 1) { + result.push_back(current_vector); + } + break; + case ',': + case ' ': + case '\t': + input_ss.get(); + break; + default: // All other characters should be part of the numbers. + if (depth != 2) { + std::stringstream err_ss; + err_ss << "Numbers at depth other than 2. Char was '" << char(input_ss.peek()) << "'."; + error_return = err_ss.str(); + return result; + } + float value; + input_ss >> value; + if (!!input_ss) { + current_vector.push_back(value); + } + break; + } + } + + if (depth != 0) { + error_return = "Unterminated vector string."; + } else { + error_return = ""; + } + + return result; +} + +std::string threadSched2Str(int thread_sched_policy) +{ + switch (thread_sched_policy) { + case SCHED_OTHER: + return "SCHED_OTHER"; + case SCHED_FIFO: + return "SCHED_FIFO"; + case SCHED_RR: + return "SCHED_RR"; +#ifdef __USE_GNU + case SCHED_BATCH: + return "SCHED_BATCH"; + case SCHED_ISO: + return "SCHED_ISO"; + case SCHED_IDLE: + return "SCHED_IDLE"; + case SCHED_DEADLINE: + return "SCHED_DEADLINE"; +#endif + default: + return ""; + } +} + +bool checkRoot() +{ + if (getuid()) { + return false; + } else { + return true; + } +} + +bool ReadCocoYaml( + const std::string & label_file, std::unordered_map & out_labels) +{ + // Open the YAML file + std::ifstream file(label_file.c_str()); + if (!file.is_open()) { + return false; + } + + // Read the file line by line + std::string line; + std::vector lines; + while (std::getline(file, line)) { + lines.push_back(line); + } + + // Find the start and end of the names section + std::size_t start = 0; + std::size_t end = 0; + for (std::size_t i = 0; i < lines.size(); i++) { + if (lines[i].find("names:") != std::string::npos) { + start = i + 1; + } else if (start > 0 && lines[i].find(':') == std::string::npos) { + end = i; + break; + } + } + + // Extract the labels + for (std::size_t i = start; i < end; i++) { + std::stringstream ss(lines[i]); + std::string class_id, label; + std::getline(ss, class_id, ':'); // Extract the number before the delimiter + // ---> remove heading spaces and tabs + class_id.erase(remove(class_id.begin(), class_id.end(), ' '), class_id.end()); + class_id.erase(remove(class_id.begin(), class_id.end(), '\t'), class_id.end()); + // <--- remove heading spaces and tabs + std::getline(ss, label); // Extract the string after the delimiter + out_labels[class_id] = label; + } + + return true; +} + + +bool isZED(sl::MODEL camModel) +{ + if (camModel == sl::MODEL::ZED) { + return true; + } + return false; +} + +bool isZEDM(sl::MODEL camModel) +{ + if (camModel == sl::MODEL::ZED_M) { + return true; + } + return false; +} + +bool isZED2OrZED2i(sl::MODEL camModel) +{ + if (camModel == sl::MODEL::ZED2) { + return true; + } + if (camModel == sl::MODEL::ZED2i) { + return true; + } + return false; +} + +bool isZEDX(sl::MODEL camModel) +{ + if (camModel == sl::MODEL::ZED_X) { + return true; + } + if (camModel == sl::MODEL::ZED_XM) { + return true; + } + if (camModel == sl::MODEL::VIRTUAL_ZED_X) { + return true; + } + return false; +} + +bool isObjDetAvailable(sl::MODEL camModel) +{ + if (camModel != sl::MODEL::ZED) { + return true; + } + return false; +} + +std::string seconds2str(double sec) +{ + int days = sec / 86400; + sec -= days * 86400; + int hours = sec / 3600; + sec -= hours * 3600; + int minutes = sec / 60; + sec -= minutes * 60; + + std::stringstream ss; + ss << days << " days, " << hours << " hours, " << minutes << " min, " << sec << " sec"; + + return ss.str(); +} + +StopWatch::StopWatch(rclcpp::Clock::SharedPtr clock) +: mStartTime(0, 0, RCL_ROS_TIME), + mClockPtr(clock) +{ + tic(); // Start the timer at creation +} + +void StopWatch::tic() +{ + mStartTime = mClockPtr->now(); // Reset the start time point +} + +double StopWatch::toc(std::string func_name) +{ + auto now = mClockPtr->now(); + + double elapsed_nsec = (now - mStartTime).nanoseconds(); + if (!func_name.empty()) { + std::cerr << func_name << " -> toc elapsed_sec: " << elapsed_nsec / 1e9 << std::endl << + std::flush; + } + + return elapsed_nsec / 1e9; // Returns elapsed time in seconds +} + +} // namespace sl_tools diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_types.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_types.cpp new file mode 100644 index 0000000000..c09497c6bf --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_types.cpp @@ -0,0 +1,48 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sl_types.hpp" + +namespace stereolabs +{ + +std::string toString(const PubRes & res) +{ + switch (res) { + case NATIVE: + return "NATIVE"; + case CUSTOM: + return "CUSTOM"; + default: + return ""; + } +} + +std::string toString(const PcRes & res) +{ + switch (res) { + case PUB: + return "PUB"; + case FULL: + return "FULL"; + case COMPACT: + return "COMPACT"; + case REDUCED: + return "REDUCED"; + default: + return ""; + } +} + +} // namespace stereolabs diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_win_avg.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_win_avg.cpp new file mode 100644 index 0000000000..bd231f07d3 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/tools/src/sl_win_avg.cpp @@ -0,0 +1,71 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sl_win_avg.hpp" + +namespace sl_tools +{ + +WinAvg::WinAvg(size_t win_size) +{ + mWinSize = win_size; + mSumVals = 0.0; +} + +WinAvg::~WinAvg() {} + +double WinAvg::setNewSize(size_t win_size) +{ + std::lock_guard guard(mQueueMux); + + mWinSize = win_size; + while (mVals.size() > mWinSize) { + double val = mVals.back(); + mVals.pop_back(); + mSumVals -= val; + } + + return mSumVals / mVals.size(); +} + +double WinAvg::addValue(double val) +{ + std::lock_guard guard(mQueueMux); + if (mVals.size() == mWinSize) { + double older = mVals.back(); + mVals.pop_back(); + mSumVals -= older; + } + + mVals.push_front(val); + mSumVals += val; + + auto avg = mSumVals / mVals.size(); + + // std::cout << "New val: " << val << " - Size: " << mVals.size() + // << " - Sum: " << mSumVals << " - Avg: " << avg << std::endl; + + return avg; +} + +double WinAvg::getAvg() +{ + std::lock_guard guard(mQueueMux); + + double avg = mSumVals / mVals.size(); + + return avg; +} + +} diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/cost_traversability.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/cost_traversability.hpp new file mode 100644 index 0000000000..bd2fbacf97 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/cost_traversability.hpp @@ -0,0 +1,71 @@ +#ifndef COST_TRAVERSABILITY_HPP +#define COST_TRAVERSABILITY_HPP__ + +#include "sl/Fusion.hpp" + +namespace stereolabs +{ +namespace cost_traversability +{ +/** +\brief Defines robot parameters, this will be used to compute the TRAVERSABILITY_COST +*/ +struct RobotParameters +{ + float radius = 0.25f; + float step_max = 0.1f; + float slope_max = 20.0f; // degrees + float roughness_max = 0.1f; +}; + +/** + \brief Defines the traversability parameters, this will be used to compute the TRAVERSABILITY_COST + */ +struct TraversabilityParameters +{ + float occupancy_threshold = 0.5f; + float slope_weight = 1.f / 3.f; + float step_weight = 1.f / 3.f; + float roughness_weight = 1.f / 3.f; +}; + +constexpr sl::LayerName TRAVERSABILITY_COST = + static_cast(static_cast(sl::LayerName::LAST) + 1); +constexpr sl::LayerName OCCUPANCY = + static_cast(static_cast(sl::LayerName::LAST) + 2); +constexpr sl::LayerName TRAVERSABILITY_COST_STEP = + static_cast(static_cast(sl::LayerName::LAST) + 3); +constexpr sl::LayerName TRAVERSABILITY_COST_SLOPE = + static_cast(static_cast(sl::LayerName::LAST) + 4); +constexpr sl::LayerName TRAVERSABILITY_COST_ROUGHNESS = + static_cast(static_cast(sl::LayerName::LAST) + 5); + +constexpr float OCCUPIED_CELL = 1.f; +constexpr float FREE_CELL = 0.f; +constexpr float INVALID_CELL_DATA = NAN; +constexpr float UNKNOWN_CELL = NAN; + +void initCostTraversibily( + sl::Terrain & cost_terrain, float resolution, float range, + float height_threshold); + +void computeCost( + sl::Terrain & elevation_terrain, sl::Terrain & cost_terrain, + const float grid_resolution, RobotParameters robot_parameters, + TraversabilityParameters traversability_parameters); + +void normalization(sl::Terrain & cost_terrain, sl::LayerName layer, sl::Mat & view); + +} // namespace cost_traversability + +} // namespace stereolabs + +// SDK internal function +namespace plane +{ +void compute_pca( + std::vector & points, sl::float3 & normal_vect, sl::float3 & centroid, + sl::float3 & eigen_values); +} + +#endif // COST_TRAVERSABILITY_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/zed_camera_component.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/zed_camera_component.hpp new file mode 100644 index 0000000000..c166497426 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/include/zed_camera_component.hpp @@ -0,0 +1,1191 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ZED_CAMERA_COMPONENT_HPP_ +#define ZED_CAMERA_COMPONENT_HPP_ + +#include +#include +#include +#include +#include + +#include + +#include "sl_version.hpp" +#include "sl_tools.hpp" +#include "sl_types.hpp" +#include "visibility_control.hpp" + +namespace stereolabs +{ + +class ZedCamera : public rclcpp::Node +{ +public: + ZED_COMPONENTS_PUBLIC + explicit ZedCamera(const rclcpp::NodeOptions & options); + + virtual ~ZedCamera(); + +protected: + // ----> Initialization functions + void initNode(); + void deInitNode(); + + void initParameters(); + void initServices(); + void initThreads(); + + void getDebugParams(); + void getTopicEnableParams(); + void getSimParams(); + void getGeneralParams(); + void getSvoParams(); + void getVideoParams(); + void getRoiParams(); + void getDepthParams(); + void getPosTrackingParams(); + void getGnssFusionParams(); + void getSensorsParams(); + void getMappingParams(); + void getOdParams(); + void getCustomOdParams(); + void getBodyTrkParams(); + void getStreamingServerParams(); + void getAdvancedParams(); + + void setTFCoordFrameNames(); + void initPublishers(); + void initVideoDepthPublishers(); + + void initSubscribers(); + + void fillCamInfo( + const std::shared_ptr & zed, + const sensor_msgs::msg::CameraInfo::SharedPtr & leftCamInfoMsg, + const sensor_msgs::msg::CameraInfo::SharedPtr & rightCamInfoMsg, + const std::string & leftFrameId, const std::string & rightFrameId, + bool rawParam = false); + + bool startCamera(); + bool startPosTracking(); + bool saveAreaMemoryFile(const std::string & filePath); + bool start3dMapping(); + void stop3dMapping(); + bool startObjDetect(); + void stopObjDetect(); + bool startBodyTracking(); + void stopBodyTracking(); + bool startSvoRecording(std::string & errMsg); + void stopSvoRecording(); + bool startStreamingServer(); + void stopStreamingServer(); + void closeCamera(); + // <---- Initialization functions + + // ----> Dynamic Parameters Handlers + // Video/Depth + bool handleVideoDepthDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + bool handleGmsl2Params( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + bool handleUsb3Params( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + bool handleCommonVideoParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + bool handleDepthParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + // Object Detection + bool handleOdDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + bool handleCustomOdDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + // Body Tracking + bool handleBodyTrkDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result); + // <---- Dynamic Parameters Handlers + + // ----> Callbacks + void callback_pubFusedPc(); + void callback_pubPaths(); + void callback_pubTemp(); + void callback_pubHeartbeat(); + void callback_gnssPubTimerTimeout(); + rcl_interfaces::msg::SetParametersResult callback_dynamicParamChange( + std::vector parameters); + void callback_updateDiagnostic( + diagnostic_updater::DiagnosticStatusWrapper & stat); + + void callback_enableDepth( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_resetOdometry( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_resetPosTracking( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_setPose( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_saveAreaMemory( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_enableObjDet( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_enableBodyTrk( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_enableMapping( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_enableStreaming( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_startSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_stopSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_pauseSvoInput( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_setSvoFrame( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_clickedPoint( + const geometry_msgs::msg::PointStamped::SharedPtr msg); + void callback_gnssFix(const sensor_msgs::msg::NavSatFix::SharedPtr msg); + void callback_clock(const rosgraph_msgs::msg::Clock::SharedPtr msg); + void callback_setRoi( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_resetRoi( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_toLL( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_fromLL( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + // <---- Callbacks + + // ----> Thread functions + // Main thread + void threadFunc_zedGrab(); + + // Video/Depth thread + void threadFunc_videoDepthElab(); + void setupVideoDepthThread(); + bool waitForVideoDepthData(std::unique_lock & lock); + void handleVideoDepthPublishing(); + // Point Cloud thread + void threadFunc_pointcloudElab(); + void setupPointCloudThread(); + bool waitForPointCloudData(std::unique_lock & lock); + void handlePointCloudPublishing(); + // Sensors thread + void threadFunc_pubSensorsData(); + // <---- Thread functions + + // ----> Publishing functions + + void publishImageWithInfo( + const sl::Mat & img, + const image_transport::Publisher & pubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t); + +#ifdef FOUND_ISAAC_ROS_NITROS + void publishImageWithInfo( + const sl::Mat & img, + const nitrosImgPub & nitrosPubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t); +#endif + void publishCameraInfo( + const camInfoPub & infoPub, + camInfoMsgPtr & camInfoMsg, const rclcpp::Time & t); + + void publishDepthMapWithInfo(const sl::Mat & depth, const rclcpp::Time & t); + void publishDisparity(const sl::Mat & disparity, const rclcpp::Time & t); + + void processVideoDepth(); + bool updateVideoDepthSubscribers(bool force = false); + bool areVideoDepthSubscribed(); + void retrieveVideoDepth(bool gpu); + bool retrieveLeftImage(bool gpu); + bool retrieveLeftRawImage(bool gpu); + bool retrieveRightImage(bool gpu); + bool retrieveRightRawImage(bool gpu); + bool retrieveLeftGrayImage(bool gpu); + bool retrieveLeftRawGrayImage(bool gpu); + bool retrieveRightGrayImage(bool gpu); + bool retrieveRightRawGrayImage(bool gpu); + bool retrieveDepthMap(bool gpu); + bool retrieveConfidence(bool gpu); + bool retrieveDisparity(); + bool retrieveDepthInfo(); + + void publishVideoDepth(rclcpp::Time & out_pub_ts); + void publishLeftAndRgbImages(const rclcpp::Time & t); + void publishLeftRawAndRgbRawImages(const rclcpp::Time & t); + void publishLeftGrayAndRgbGrayImages(const rclcpp::Time & t); + void publishLeftRawGrayAndRgbRawGrayImages(const rclcpp::Time & t); + void publishRightImages(const rclcpp::Time & t); + void publishRightRawImages(const rclcpp::Time & t); + void publishRightGrayImages(const rclcpp::Time & t); + void publishRightRawGrayImages(const rclcpp::Time & t); + void publishStereoImages(const rclcpp::Time & t); + void publishStereoRawImages(const rclcpp::Time & t); + void publishDepthImage(const rclcpp::Time & t); + void publishConfidenceMap(const rclcpp::Time & t); + void publishDisparityImage(const rclcpp::Time & t); + void publishDepthInfo(const rclcpp::Time & t); + void publishCameraInfos(); // Used to publish camera infos when no video/depth is subscribed + + void checkRgbDepthSync(); + bool checkGrabAndUpdateTimestamp(rclcpp::Time & out_pub_ts); + + void processPointCloud(); + bool isPointCloudSubscribed(); + void publishPointCloud(); + void publishImuFrameAndTopic(); + + void publishOdom( + tf2::Transform & odom2baseTransf, sl::Pose & slPose, const tf2::Vector3 & linear_velocity, + const tf2::Vector3 & angular_velocity, + rclcpp::Time t); + void publishPose(); + void publishPoseLandmarks(); + void publishGnssPose(); + void publishPoseStatus(); + void publishGnssPoseStatus(); + void publishGeoPoseStatus(); + void publishTFs(rclcpp::Time t); + void publishCameraTFs(rclcpp::Time t); + void publishOdomTF(rclcpp::Time t); + void publishPoseTF(rclcpp::Time t); + bool publishSensorsData(rclcpp::Time force_ts = TIMEZERO_ROS); + void publishHealthStatus(); + bool publishSvoStatus(uint64_t frame_ts); + + void publishClock(const sl::Timestamp & ts); + // <---- Publishing functions + + // ----> Utility functions + bool isDepthRequired(); + bool updatePosTrackingSubscribers(bool force = false); + bool isPosTrackingRequired(); + + void applyVideoSettings(); + void applyAutoExposureGainSettings(); + void applyExposureGainSettings(); + void applyWhiteBalanceSettings(); + void applyBrightnessContrastHueSettings(); + void applySaturationSharpnessGammaSettings(); + void applyZEDXSettings(); + void applyZEDXExposureSettings(); + void applyZEDXAutoExposureTimeRange(); + void applyZEDXExposureCompensation(); + void applyZEDXAnalogDigitalGain(); + void applyZEDXAutoAnalogGainRange(); + void applyZEDXAutoDigitalGainRange(); + void applyZEDXDenoising(); + + void applyDepthSettings(); + + void processOdometry(); + void processPose(); + void processGeoPose(); + void processSvoGnssData(); + + void processDetectedObjects(rclcpp::Time t); + void processBodies(rclcpp::Time t); + + void processRtRoi(rclcpp::Time t); + + bool setPose(float xt, float yt, float zt, float rr, float pr, float yr); + void initTransforms(); + bool getSens2BaseTransform(); + bool getSens2CameraTransform(); + bool getCamera2BaseTransform(); + bool getGnss2BaseTransform(); + + void startFusedPcTimer(double fusedPcRate); + void startPathPubTimer(double pathTimerRate); + void startTempPubTimer(); + void startHeartbeatTimer(); + + // Region of Interest + std::string getParam( + std::string paramName, + std::vector> & outVal); + std::string parseRoiPoly( + const std::vector> & in_poly, + std::vector & out_poly); + // <---- Utility functions + +private: + // ZED SDK + std::shared_ptr mZed; + sl::InitParameters mInitParams; + sl::RuntimeParameters mRunParams; + + // ----> Fusion module + std::shared_ptr mFusionConfig; + sl::Fusion mFusion; + sl::InitFusionParameters mFusionInitParams; + sl::CameraIdentifier mCamUuid; + // <---- Fusion module + + uint64_t mFrameCount = 0; + uint32_t mSvoLoopCount = 0; + + // ----> Topics + std::string mTopicRoot = "~/"; + + // Image Topics + std::string mLeftTopic; + std::string mLeftRawTopic; + std::string mRightTopic; + std::string mRightRawTopic; + std::string mRgbTopic; + std::string mRgbRawTopic; + std::string mStereoTopic; + std::string mStereoRawTopic; + std::string mLeftGrayTopic; + std::string mLeftRawGrayTopic; + std::string mRightGrayTopic; + std::string mRightRawGrayTopic; + std::string mRgbGrayTopic; + std::string mRgbRawGrayTopic; + + // Depth Topics + std::string mDisparityTopic; + std::string mDepthTopic; + std::string mDepthInfoTopic; + std::string mConfMapTopic; + std::string mPointcloudTopic; + + // Localization Topics + std::string mOdomTopic; + std::string mPoseTopic; + std::string mPoseStatusTopic; + std::string mPoseCovTopic; + std::string mGnssPoseTopic; + std::string mGnssPoseStatusTopic; + std::string mGeoPoseTopic; + std::string mGeoPoseStatusTopic; + std::string mFusedFixTopic; + std::string mOriginFixTopic; + std::string mPointcloudFusedTopic; + std::string mPointcloud3DLandmarksTopic; + std::string mObjectDetTopic; + std::string mBodyTrkTopic; + std::string mOdomPathTopic; + std::string mPosePathTopic; + std::string mClickedPtTopic; // Clicked point + std::string mRoiMaskTopic; + // <---- Topics + + // ----> Parameter variables + // Debug + bool _debugCommon = false; + bool _debugDynParams = false; + bool _debugGrab = false; + bool _debugSim = false; + bool _debugVideoDepth = false; + bool _debugCamCtrl = false; + bool _debugPointCloud = false; + bool _debugTf = false; + bool _debugPosTracking = false; + bool _debugGnss = false; + bool _debugSensors = false; + bool _debugMapping = false; + bool _debugObjectDet = false; + bool _debugBodyTrk = false; + bool _debugAdvanced = false; + bool _debugRoi = false; + bool _debugStreaming = false; + bool _debugNitros = false; + // If available, force disable NITROS usage for debugging and testing + // purposes; otherwise, this is always true. + bool _nitrosDisabled = true; + + // Topic Enablers +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + bool m24bitMode = false; +#endif + bool mPublishSensImu = true; + bool mPublishSensImuRaw = false; + bool mPublishSensMag = false; + bool mPublishSensBaro = false; + bool mPublishSensTemp = false; + bool mPublishSensImuTransf = false; + bool mPublishImgLeftRight = false; + bool mPublishImgRaw = false; + bool mPublishImgGray = false; + bool mPublishImgRgb = true; + bool mPublishImgStereo = false; + bool mPublishImgRoiMask = false; + bool mPublishOdomPose = true; + bool mPublishPoseCov = false; + bool mPublishPath = false; + bool mPublishDetPlane = false; + bool mPublishDepthMap = true; + bool mPublishDepthInfo = false; + bool mPublishPointcloud = true; + bool mPublishConfidence = false; + bool mPublishDisparity = false; + bool mPublishStatus = true; + bool mPublishSvoClock = false; + + // General + int mCamSerialNumber = 0; + int mCamId = -1; + std::vector mCamVirtualSerialNumbers; + std::vector mCamVirtualCameraIds; + bool mSimMode = false; // Expecting simulation data? + bool mUseSimTime = false; // Use sim time? + std::string mSimAddr = + "127.0.0.1"; // The local address of the machine running the simulator + int mSimPort = 30000; // The port to be used to connect to the simulator + + bool mStreamMode = false; // Expecting local streaming data? + std::string mStreamAddr = ""; // The local address of the streaming server + int mStreamPort = 30000; // The port to be used to connect to a local streaming server + + sl::MODEL mCamUserModel = sl::MODEL::ZED2i; // Default camera model + sl::MODEL mCamRealModel; // Camera model requested to SDK + unsigned int mCamFwVersion; // Camera FW version + unsigned int mSensFwVersion; // Sensors FW version + std::string mCameraName = "zed"; // Default camera name + int mCamGrabFrameRate = 15; + double mGrabComputeCappingFps = 0.0; + bool mAsyncImageRetrieval = false; + int mImageValidityCheck = 1; + std::string mSvoFilepath = ""; +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + std::string mSvoDecryptionKey = ""; +#endif + bool mSvoLoop = false; + bool mSvoRealtime = false; + int mSvoFrameStart = 0; + double mSvoRate = 1.0; + double mSvoExpectedPeriod = 0.0; + bool mUseSvoTimestamp = false; + bool mUsePubTimestamps = false; + bool mGrabOnce = false; + bool mGrabImuOnce = false; + int mVerbose = 1; + std::string mVerboseLogFile = ""; + int mGpuId = -1; + std::string mOpencvCalibFile; + sl::RESOLUTION mCamResol = sl::RESOLUTION::AUTO; // Default resolution: AUTOMATIC + PubRes mPubResolution = PubRes::NATIVE; // Use native grab resolution by default + double mCustomDownscaleFactor = 1.0; // Used to rescale data with user factor + bool mOpenniDepthMode = + false; // 16 bit UC data in mm else 32F in m, + // for more info -> http://www.ros.org/reps/rep-0118.html + double mCamMinDepth = 0.01; + double mCamMaxDepth = 15.0; + sl::DEPTH_MODE mDepthMode = sl::DEPTH_MODE::NEURAL; + std::string mDepthModelOverride; // Optional model file override for depth mode + PcRes mPcResolution = PcRes::COMPACT; + std::atomic mDepthDisabled = false; // Indicates if depth calculation is not required (DEPTH_MODE::NONE) + int mDepthStabilization = 0; + + int mCamTimeoutSec = 5; + int mMaxReconnectTemp = 5; + bool mCameraSelfCalib = true; + bool mCameraFlip = false; + + + bool mSensCameraSync = false; + double mSensPubRate = 200.; + + std::vector> mRoyPolyParam; // Manual ROI polygon + bool mAutoRoiEnabled = false; + bool mManualRoiEnabled = false; + float mRoiDepthFarThresh = 2.5f; + float mRoiImgHeightRationCutOff = 0.5f; + std::unordered_set mRoiModules; + + bool mPosTrackingEnabled = false; + bool mPublishTF = false; + bool mPublishMapTF = false; + bool mPublishImuTF = false; + bool mPoseSmoothing = false; + bool mAreaMemory = true; + std::string mAreaMemoryFilePath = ""; + bool mLocalizationOnly = false; + sl::POSITIONAL_TRACKING_MODE mPosTrkMode = + sl::POSITIONAL_TRACKING_MODE::GEN_1; + bool mSaveAreaMemoryOnClosing = true; + bool mImuFusion = true; + bool mFloorAlignment = false; + bool mTwoDMode = false; + float mFixedZValue = 0.0; + std::vector mInitialBasePose = std::vector(6, 0.0); + bool mResetOdomWhenLoopClosure = true; + bool mResetPoseWithSvoLoop = true; + bool mPublish3DLandmarks = false; + uint8_t mPublishLandmarkSkipFrame = 15; + double mPathPubRate = 2.0; + double mTfOffset = 0.0; + float mPosTrackDepthMinRange = 0.0f; + bool mSetAsStatic = false; + bool mSetGravityAsOrigin = false; + int mPathMaxCount = -1; + + bool mGnssFusionEnabled = false; + std::string mGnssTopic = "/gps/fix"; + bool mGnssEnableReinitialization = true; + bool mGnssEnableRollingCalibration = true; + bool mGnssEnableTranslationUncertaintyTarget = false; + double mGnssVioReinitThreshold = 5.0; + double mGnssTargetTranslationUncertainty = 0.1; + double mGnssTargetYawUncertainty = 0.1; + double mGnssHcovMul = 1.0; + double mGnssVcovMul = 1.0; + bool mGnssZeroAltitude = false; + bool mPublishUtmTf = true; + bool mUtmAsParent = true; + + bool mMappingEnabled = false; + float mMappingRes = 0.05f; + float mMappingRangeMax = 10.0f; + + bool mObjDetEnabled = false; + bool mObjDetTracking = true; + double mObjDetPredTimeout = 0.5; + bool mObjDetReducedPrecision = false; + double mObjDetMaxRange = 15.0; + std::vector mObjDetFilter; + std::map mObjDetClassConfMap; + bool mObjDetPeopleEnable = true; + double mObjDetPeopleConf = 50.0; + bool mObjDetVehiclesEnable = true; + double mObjDetVehiclesConf = 50.0; + bool mObjDetBagsEnable = true; + double mObjDetBagsConf = 50.0; + bool mObjDetAnimalsEnable = true; + double mObjDetAnimalsConf = 50.0; + bool mObjDetElectronicsEnable = true; + double mObjDetElectronicsConf = 50.0; + bool mObjDetFruitsEnable = true; + double mObjDetFruitsConf = 50.0; + bool mObjDetSportEnable = true; + double mObjDetSportConf = 50.0; + bool mObjDetRtParamsDirty = true; // Force initial setRuntimeParameters call + sl::OBJECT_DETECTION_MODEL mObjDetModel = + sl::OBJECT_DETECTION_MODEL::MULTI_CLASS_BOX_FAST; + sl::OBJECT_FILTERING_MODE mObjFilterMode = sl::OBJECT_FILTERING_MODE::NMS3D; + std::string mYoloOnnxPath = ""; + int mYoloOnnxSize = 512; + int mCustomClassCount = 1; + std::unordered_map mCustomOdProperties; + std::unordered_map mCustomLabels; + std::unordered_map mCustomClassIdMap; + + bool mBodyTrkEnabled = false; + sl::BODY_TRACKING_MODEL mBodyTrkModel = + sl::BODY_TRACKING_MODEL::HUMAN_BODY_FAST; + sl::BODY_FORMAT mBodyTrkFmt = sl::BODY_FORMAT::BODY_38; + bool mBodyTrkReducedPrecision = false; + double mBodyTrkMaxRange = 15.0f; + sl::BODY_KEYPOINTS_SELECTION mBodyTrkKpSelection = + sl::BODY_KEYPOINTS_SELECTION::FULL; + bool mBodyTrkFitting = true; + bool mBodyTrkEnableTracking = true; + double mBodyTrkPredTimeout = 0.5; + double mBodyTrkConfThresh = 50.0; + int mBodyTrkMinKp = 10; + bool mBodyTrkRtParamsDirty = true; // Force initial setRuntimeParameters call + + double mPdMaxDistanceThreshold = 0.15; + double mPdNormalSimilarityThreshold = 15.0; + + bool mChangeThreadSched = false; + std::string mThreadSchedPolicy; + int mThreadPrioGrab = 50; + int mThreadPrioSens = 70; + int mThreadPrioPointCloud = 60; + + std::atomic mStreamingServerRequired; + sl::STREAMING_CODEC mStreamingServerCodec = sl::STREAMING_CODEC::H264; + int mStreamingServerPort = 30000; + int mStreamingServerBitrate = 12500; + int mStreamingServerGopSize = -1; + bool mStreamingServerAdaptiveBitrate = false; + int mStreamingServerChunckSize = 16084; + int mStreamingServerTargetFramerate = 0; + // <---- Parameter variables + + // ----> Dynamic params + OnSetParametersCallbackHandle::SharedPtr mParamChangeCallbackHandle; + + double mVdPubRate = 15.0; + int mCamBrightness = 4; + int mCamContrast = 4; + int mCamHue = 0; + int mCamSaturation = 4; + int mCamSharpness = 4; + int mCamGamma = 8; + bool mCamAutoExpGain = true; + int mCamGain = 80; + int mCamExposure = 80; + bool mCamAutoWB = true; + int mCamWBTemp = 42; + int mDepthConf = 95; + int mDepthTextConf = 100; + double mPcPubRate = 10.0; + double mFusedPcPubRate = 1.0; + bool mRemoveSatAreas = true; + + int mGmslExpTime = 16666; + int mGmslAutoExpTimeRangeMin = 28; + int mGmslAutoExpTimeRangeMax = 30000; + int mGmslExposureComp = 50; + int mGmslAnalogGain = 8000; + int mGmslAnalogGainRangeMin = 1000; + int mGmslAnalogGainRangeMax = 16000; + int mGmslDigitalGain = 128; + int mGmslAutoDigitalGainRangeMin = 1; + int mGmslAutoDigitalGainRangeMax = 256; + int mGmslDenoising = 50; + // <---- Dynamic params + + // ----> QoS + // https://github.com/ros2/ros2/wiki/About-Quality-of-Service-Settings + rclcpp::QoS mQos; + rclcpp::PublisherOptions mPubOpt; + rclcpp::SubscriptionOptions mSubOpt; + // <---- QoS + + // ----> Frame IDs + bool mStaticTfPublished = false; + bool mStaticImuTfPublished = false; + + std::string mBaseFrameId = ""; + std::string mCenterFrameId = ""; + + std::string mRightCamFrameId = ""; + std::string mRightCamOptFrameId = ""; + std::string mLeftCamFrameId = ""; + std::string mLeftCamOptFrameId = ""; + + std::string mImuFrameId = ""; + std::string mBaroFrameId = ""; + std::string mMagFrameId = ""; + std::string mTempLeftFrameId = ""; + std::string mTempRightFrameId = ""; + + std::string mDepthFrameId = ""; + std::string mDepthOptFrameId = ""; + + std::string mPointCloudFrameId = ""; + + std::string mUtmFrameId = "utm"; + std::string mMapFrameId = "map"; + std::string mOdomFrameId = "odom"; + std::string mGnssFrameId = ""; + std::string mGnssOriginFrameId = "gnss_ref_pose"; + // <---- Frame IDs + + // ----> Stereolabs Mat Info + int mCamWidth; // Camera frame width + int mCamHeight; // Camera frame height + sl::Resolution mMatResol; + sl::Resolution mPcResol; + // <---- Stereolabs Mat Info + + // Camera IMU transform + sl::Transform mSlCamImuTransf; + + // ----> initialization Transform listener + std::unique_ptr mTfBuffer; + std::unique_ptr mTfListener; + std::unique_ptr mStaticTfBroadcaster; + std::unique_ptr mTfBroadcaster; + // <---- initialization Transform listener + + // ----> TF Transforms + tf2::Transform + mMap2OdomTransf; // Coordinates of the odometry frame in map frame + tf2::Transform mOdom2BaseTransf; // Coordinates of the base in odometry frame + tf2::Transform mMap2BaseTransf; // Coordinates of the base in map frame + tf2::Transform + mSensor2BaseTransf; // Coordinates of the base frame in sensor frame + tf2::Vector3 linear_base; // Linear twist in the camera base link frame + tf2::Vector3 angular_base; // Angular twist in the camera base link frame + tf2::Transform + mSensor2CameraTransf; // Coordinates of the camera frame in sensor frame + tf2::Transform + mCamera2BaseTransf; // Coordinates of the base frame in camera frame + tf2::Transform mMap2UtmTransf; // Coordinates of the UTM frame in map frame + tf2::Transform + mGnss2BaseTransf; // Coordinates of the base in GNSS sensor frame + // <---- TF Transforms + + // ----> TF Transforms Flags + bool mSensor2BaseTransfValid = false; + bool mSensor2BaseTransfFirstErr = true; + bool mSensor2CameraTransfValid = false; + bool mSensor2CameraTransfFirstErr = true; + bool mCamera2BaseTransfValid = false; + bool mCamera2BaseFirstErr = true; + bool mGnss2BaseTransfValid = false; + bool mGnss2BaseTransfFirstErr = true; + bool mMap2UtmTransfValid = false; + + + // <---- TF Transforms Flags + + // ----> Messages (ONLY THOSE NOT CHANGING WHILE NODE RUNS) + // Camera infos + camInfoMsgPtr mLeftCamInfoMsg; + camInfoMsgPtr mRightCamInfoMsg; + camInfoMsgPtr mLeftCamInfoRawMsg; + camInfoMsgPtr mRightCamInfoRawMsg; + // <---- Messages + + // ----> Publishers + clockPub mPubClock; + + // Image publishers with camera info + image_transport::Publisher mPubRgb; + image_transport::Publisher mPubRawRgb; + image_transport::Publisher mPubLeft; + image_transport::Publisher mPubRawLeft; + image_transport::Publisher mPubRight; + image_transport::Publisher mPubRawRight; + image_transport::Publisher mPubRgbGray; + image_transport::Publisher mPubRawRgbGray; + image_transport::Publisher mPubLeftGray; + image_transport::Publisher mPubRawLeftGray; + image_transport::Publisher mPubRightGray; + image_transport::Publisher mPubRawRightGray; + image_transport::Publisher mPubRoiMask; + image_transport::Publisher mPubDepth; + image_transport::Publisher mPubConfMap; +#ifdef FOUND_ISAAC_ROS_NITROS + // Nitros image publishers with camera info + nitrosImgPub mNitrosPubRgb; + nitrosImgPub mNitrosPubRawRgb; + nitrosImgPub mNitrosPubLeft; + nitrosImgPub mNitrosPubRawLeft; + nitrosImgPub mNitrosPubRight; + nitrosImgPub mNitrosPubRawRight; + nitrosImgPub mNitrosPubRgbGray; + nitrosImgPub mNitrosPubRawRgbGray; + nitrosImgPub mNitrosPubLeftGray; + nitrosImgPub mNitrosPubRawLeftGray; + nitrosImgPub mNitrosPubRightGray; + nitrosImgPub mNitrosPubRawRightGray; + nitrosImgPub mNitrosPubRoiMask; + nitrosImgPub mNitrosPubDepth; + nitrosImgPub mNitrosPubConfMap; +#endif + + // Image publishers without camera info (no NITROS) + image_transport::Publisher mPubStereo; + image_transport::Publisher mPubRawStereo; + + // Camera Info publishers + camInfoPub mPubRgbCamInfo; + camInfoPub mPubRawRgbCamInfo; + camInfoPub mPubLeftCamInfo; + camInfoPub mPubRawLeftCamInfo; + camInfoPub mPubRightCamInfo; + camInfoPub mPubRawRightCamInfo; + camInfoPub mPubRgbGrayCamInfo; + camInfoPub mPubRawRgbGrayCamInfo; + camInfoPub mPubLeftGrayCamInfo; + camInfoPub mPubRawLeftGrayCamInfo; + camInfoPub mPubRightGrayCamInfo; + camInfoPub mPubRawRightGrayCamInfo; + camInfoPub mPubRoiMaskCamInfo; + camInfoPub mPubDepthCamInfo; + camInfoPub mPubConfMapCamInfo; + camInfoPub mPubRgbCamInfoTrans; + camInfoPub mPubRawRgbCamInfoTrans; + camInfoPub mPubLeftCamInfoTrans; + camInfoPub mPubRawLeftCamInfoTrans; + camInfoPub mPubRightCamInfoTrans; + camInfoPub mPubRawRightCamInfoTrans; + camInfoPub mPubRgbGrayCamInfoTrans; + camInfoPub mPubRawRgbGrayCamInfoTrans; + camInfoPub mPubLeftGrayCamInfoTrans; + camInfoPub mPubRawLeftGrayCamInfoTrans; + camInfoPub mPubRightGrayCamInfoTrans; + camInfoPub mPubRawRightGrayCamInfoTrans; + camInfoPub mPubRoiMaskCamInfoTrans; + camInfoPub mPubDepthCamInfoTrans; + camInfoPub mPubConfMapCamInfoTrans; + +#ifdef FOUND_POINT_CLOUD_TRANSPORT + point_cloud_transport::Publisher mPubCloud; + point_cloud_transport::Publisher mPubFusedCloud; + point_cloud_transport::Publisher mPub3DLandmarks; +#else + pointcloudPub mPubCloud; + pointcloudPub mPubFusedCloud; + pointcloudPub mPub3DLandmarks; +#endif + + svoStatusPub mPubSvoStatus; + healthStatusPub mPubHealthStatus; + heartbeatStatusPub mPubHeartbeatStatus; + disparityPub mPubDisparity; + posePub mPubPose; + poseStatusPub mPubPoseStatus; + poseCovPub mPubPoseCov; + odomPub mPubOdom; + odomPub mPubGnssPose; + int mFrameSkipCountLandmarks = 0; + gnssFusionStatusPub mPubGnssPoseStatus; + pathPub mPubOdomPath; + pathPub mPubPosePath; + imuPub mPubImu; + imuPub mPubImuRaw; + tempPub mPubImuTemp; + magPub mPubImuMag; + pressPub mPubPressure; + tempPub mPubTempL; + tempPub mPubTempR; + transfPub mPubCamImuTransf; + objPub mPubObjDet; + objPub mPubBodyTrk; + depthInfoPub mPubDepthInfo; + planePub mPubPlane; + markerPub mPubMarker; + + geoPosePub mPubGeoPose; + gnssFusionStatusPub mPubGeoPoseStatus; + gnssFixPub mPubFusedFix; + gnssFixPub mPubOriginFix; + // <---- Publishers + + // <---- Publisher variables + sl::Timestamp mSdkGrabTS = 0; + size_t mRgbSubCount = 0; + size_t mRgbRawSubCount = 0; + size_t mRgbGraySubCount = 0; + size_t mRgbGrayRawSubCount = 0; + size_t mLeftSubCount = 0; + size_t mLeftRawSubCount = 0; + size_t mLeftGraySubCount = 0; + size_t mLeftGrayRawSubCount = 0; + size_t mRightSubCount = 0; + size_t mRightRawSubCount = 0; + size_t mRightGraySubCount = 0; + size_t mRightGrayRawSubCount = 0; + size_t mStereoSubCount = 0; + size_t mStereoRawSubCount = 0; + size_t mDepthSubCount = 0; + size_t mConfMapSubCount = 0; + size_t mDisparitySubCount = 0; + size_t mDepthInfoSubCount = 0; + size_t mPcSubCount = 0; + std::chrono::steady_clock::time_point mLastVideoDepthSubCountQuery; + bool mVideoDepthSubCountInit = false; + size_t mPosTrackingSubCount = 0; + std::chrono::steady_clock::time_point mLastPosTrackingSubCountQuery; + bool mPosTrackingSubCountInit = false; + + sl::Mat mMatLeft, mMatLeftRaw; + sl::Mat mMatRight, mMatRightRaw; + sl::Mat mMatLeftGray, mMatLeftRawGray; + sl::Mat mMatRightGray, mMatRightRawGray; + sl::Mat mMatDepth, mMatDisp, mMatConf; + + float mMinDepth = 0.0f; + float mMaxDepth = 0.0f; + // <---- Publisher variables + + // ----> Point cloud variables + sl::Mat mMatCloud; + sl::FusedPointCloud mFusedPC; + sensor_msgs::msg::PointCloud2 mPcMsg; // Reused across frames to avoid per-frame allocation + // <---- Point cloud variables + + // ----> Subscribers + clickedPtSub mClickedPtSub; + gnssFixSub mGnssFixSub; + clockSub mClockSub; + // <---- Subscribers + + // ----> Threads and Timers + sl::ERROR_CODE mGrabStatus; + sl::ERROR_CODE mConnStatus; + sl::FUSION_ERROR_CODE mFusionStatus = sl::FUSION_ERROR_CODE::MODULE_NOT_ENABLED; + std::thread mGrabThread; // Main grab thread + std::thread mVdThread; // Video and Depth data processing thread + std::thread mPcThread; // Point Cloud publish thread + std::thread mSensThread; // Sensors data publish thread + std::atomic mThreadStop; + std::atomic mNodeDeinitialized; + rclcpp::TimerBase::SharedPtr mInitTimer; + rclcpp::TimerBase::SharedPtr mPathTimer; + rclcpp::TimerBase::SharedPtr mFusedPcTimer; + rclcpp::TimerBase::SharedPtr + mTempPubTimer; // Timer to retrieve and publish CMOS temperatures + rclcpp::TimerBase::SharedPtr mGnssPubCheckTimer; + rclcpp::TimerBase::SharedPtr mHeartbeatTimer; + double mSensRateComp = 1.0; + // <---- Threads and Timers + + // ----> Thread Sync + std::mutex mRecMutex; + std::mutex mDynParMutex; + std::mutex mMappingMutex; + std::mutex mObjDetMutex; + std::mutex mBodyTrkMutex; + std::mutex mPcMutex; + std::mutex mCloseCameraMutex; + std::mutex mPtMutex; + std::condition_variable mPcDataReadyCondVar; + std::atomic_bool mPcDataReady; + std::mutex mVdMutex; + std::condition_variable mVdDataReadyCondVar; + std::atomic_bool mVdDataReady; + // <---- Thread Sync + + // ----> Status Flags + bool mDebugMode = false; // Debug mode active? + bool mSvoMode = false; + std::atomic mSvoPause{false}; + int mSvoFrameId = 0; + int mSvoFrameCount = 0; + bool mPosTrackingStarted = false; + std::atomic_bool mPoseLocked = false; + std::atomic mPoseLockCount{0}; + bool mVdPublishing = false; // Indicates if video and depth data are + // subscribed and then published + bool mPcPublishing = + false; // Indicates if point cloud data are subscribed and then published + bool mTriggerAutoExpGain = true; // Triggered on start + bool mTriggerAutoWB = true; // Triggered on start + bool mCamSettingsDirty = true; // Force initial apply on start + bool mRecording = false; + sl::RecordingStatus mRecStatus = sl::RecordingStatus(); + bool mPosTrackingReady = false; + + sl::FusedPositionalTrackingStatus mFusedPosTrackingStatus; + sl::PositionalTrackingStatus mPosTrackingStatus; + + sl::REGION_OF_INTEREST_AUTO_DETECTION_STATE mAutoRoiStatus = + sl::REGION_OF_INTEREST_AUTO_DETECTION_STATE::NOT_ENABLED; + + bool mAreaFileExists = false; + bool mResetOdomFromSrv = false; + bool mSpatialMappingRunning = false; + bool mObjDetRunning = false; + bool mBodyTrkRunning = false; + bool mRgbSubscribed = false; + bool mGnssMsgReceived = false; // Indicates if a NavSatFix topic has been + // received, also with invalid position fix + bool mGnssFixValid = false; // Used to keep track of signal loss + bool mGnssFixNew = false; // Used to keep track of signal loss + std::string mGnssServiceStr = ""; + uint16_t mGnssService; + std::atomic mClockAvailable; // Indicates if the "/clock" topic is + // published when `use_sim_time` is true + + std::atomic mStreamingServerRunning; + + bool mUsingCustomOd = false; + uint64_t mHeartbeatCount = 0; + // <---- Status Flags + + // ----> Positional Tracking + sl::Pose mLastZedPose; + sl::Pose mLastZedDeltaOdom; + sl::Transform mInitialPoseSl; + std::vector mOdomPath; + std::vector mPosePath; + sl::GeoPose mLastGeoPose; + sl::ECEF mLastEcefPose; + sl::UTM mLastUtmPose; + sl::LatLng mLastLatLongPose; + double mLastHeading; + tf2::Quaternion mLastHeadingQuat; + sl::ECEF mInitEcefPose; + sl::UTM mInitUtmPose; + sl::LatLng mInitLatLongPose; + double mInitHeading; + bool mGnssInitGood = false; + sl::float3 mGnssAntennaPose; + // <---- Positional Tracking + + // ----> Diagnostic + sl_tools::StopWatch mUptimer; + bool mUsingIPC = false; + float mTempImu = NOT_VALID_TEMP; + float mTempLeft = NOT_VALID_TEMP; + float mTempRight = NOT_VALID_TEMP; + std::unique_ptr mElabPeriodMean_sec; + std::unique_ptr mGrabPeriodMean_sec; + std::unique_ptr mVideoDepthPeriodMean_sec; + std::unique_ptr mVideoDepthElabMean_sec; + std::unique_ptr mPcPeriodMean_sec; + std::unique_ptr mPcProcMean_sec; + std::unique_ptr mImuPeriodMean_sec; + std::unique_ptr mBaroPeriodMean_sec; + std::unique_ptr mMagPeriodMean_sec; + std::unique_ptr mObjDetPeriodMean_sec; + std::unique_ptr mObjDetElabMean_sec; + std::unique_ptr mBodyTrkPeriodMean_sec; + std::unique_ptr mBodyTrkElabMean_sec; + std::unique_ptr mPubFusedCloudPeriodMean_sec; + std::unique_ptr mPubOdomTF_sec; + std::unique_ptr mPubPoseTF_sec; + std::unique_ptr mPubImuTF_sec; + std::unique_ptr mGnssFix_sec; + bool mImuPublishing = false; + bool mMagPublishing = false; + bool mBaroPublishing = false; + bool mObjDetSubscribed = false; + bool mBodyTrkSubscribed = false; + + diagnostic_updater::Updater mDiagUpdater; // Diagnostic Updater + + sl_tools::StopWatch mImuTfFreqTimer; + sl_tools::StopWatch mGrabFreqTimer; + sl_tools::StopWatch mImuFreqTimer; + sl_tools::StopWatch mBaroFreqTimer; + sl_tools::StopWatch mMagFreqTimer; + sl_tools::StopWatch mOdomFreqTimer; + sl_tools::StopWatch mPoseFreqTimer; + sl_tools::StopWatch mPcPubFreqTimer; + sl_tools::StopWatch mVdPubFreqTimer; + sl_tools::StopWatch mSensPubFreqTimer; + sl_tools::StopWatch mOdFreqTimer; + sl_tools::StopWatch mBtFreqTimer; + sl_tools::StopWatch mPcFreqTimer; + sl_tools::StopWatch mGnssFixFreqTimer; + + int mSysOverloadCount = 0; + // <---- Diagnostic + + // ----> Timestamps + sl::Timestamp mLastTs_grab = 0; // Used to calculate stable publish frequency + rclcpp::Time mFrameTimestamp; + rclcpp::Time mGnssTimestamp; + rclcpp::Time mLastTs_imu; + rclcpp::Time mLastTs_baro; + rclcpp::Time mLastTs_mag; + rclcpp::Time mLastTs_odom; + rclcpp::Time mLastTs_pose; + rclcpp::Time mLastTs_pc; + rclcpp::Time mPrevTs_pc; + uint64_t mLastTs_gnss_nsec = 0; + rclcpp::Time mLastClock; + // <---- Timestamps + + // ----> SVO Recording parameters + unsigned int mSvoRecBitrate = 0; + sl::SVO_COMPRESSION_MODE mSvoRecCompression = sl::SVO_COMPRESSION_MODE::H265; + unsigned int mSvoRecFramerate = 0; + bool mSvoRecTranscode = false; + std::string mSvoRecFilename; + // <---- SVO Recording parameters + + // ----> Services + enableDepthPtr mEnableDepthSrv; + resetOdomSrvPtr mResetOdomSrv; + resetPosTrkSrvPtr mResetPosTrkSrv; + setPoseSrvPtr mSetPoseSrv; + saveAreaMemorySrvPtr mSaveAreaMemorySrv; + enableObjDetPtr mEnableObjDetSrv; + enableBodyTrkPtr mEnableBodyTrkSrv; + enableMappingPtr mEnableMappingSrv; + startSvoRecSrvPtr mStartSvoRecSrv; + stopSvoRecSrvPtr mStopSvoRecSrv; + pauseSvoSrvPtr mPauseSvoSrv; + setSvoFramePtr mSetSvoFrameSrv; + setRoiSrvPtr mSetRoiSrv; + resetRoiSrvPtr mResetRoiSrv; + toLLSrvPtr mToLlSrv; + fromLLSrvPtr mFromLlSrv; + enableStreamingPtr mEnableStreamingSrv; + + sl_tools::StopWatch mSetSvoFrameCheckTimer; + // <---- Services + + // ----> Services names + const std::string mSrvEnableDepthName = "enable_depth"; + const std::string mSrvResetOdomName = "reset_odometry"; + const std::string mSrvResetPoseName = "reset_pos_tracking"; + const std::string mSrvSetPoseName = "set_pose"; + const std::string mSrvSaveAreaMemoryName = "save_area_memory"; + const std::string mSrvEnableObjDetName = "enable_obj_det"; + const std::string mSrvEnableBodyTrkName = "enable_body_trk"; + const std::string mSrvEnableMappingName = "enable_mapping"; + const std::string mSrvEnableStreamingName = "enable_streaming"; + const std::string mSrvStartSvoRecName = "start_svo_rec"; + const std::string mSrvStopSvoRecName = "stop_svo_rec"; + const std::string mSrvToggleSvoPauseName = "toggle_svo_pause"; + const std::string mSrvSetSvoFrameName = "set_svo_frame"; + const std::string mSrvSetRoiName = "set_roi"; + const std::string mSrvResetRoiName = "reset_roi"; + const std::string mSrvToLlName = "toLL"; // Convert from `map` to `Lat Long` + const std::string mSrvFromLlName = "fromLL"; // Convert from `Lat Long` to `map` + // <---- Services names + + // ----> SVO v2 + std::unique_ptr mGnssReplay; + // <---- SVO v2 +}; + +} // namespace stereolabs + +#endif // ZED_CAMERA_COMPONENT_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/cost_traversability.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/cost_traversability.cpp new file mode 100644 index 0000000000..3bcaf29cf3 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/cost_traversability.cpp @@ -0,0 +1,194 @@ +#include "cost_traversability.hpp" + +namespace stereolabs +{ +namespace cost_traversability +{ +template +T clamp(T const & v, T const & lo, T const & hi) +{ + return (v < lo) ? lo : ((v > hi) ? hi : v); +} + +void initCostTraversibily( + sl::Terrain & cost_terrain, float resolution, float range, + float height_threshold) +{ + std::vector layers; + layers.push_back(TRAVERSABILITY_COST); + layers.push_back(OCCUPANCY); + layers.push_back(TRAVERSABILITY_COST_STEP); + layers.push_back(TRAVERSABILITY_COST_SLOPE); + layers.push_back(TRAVERSABILITY_COST_ROUGHNESS); + + auto range_cell = round(range / resolution); + cost_terrain.init(resolution, range_cell, layers); +} + +void computeCost( + sl::Terrain & elevation_terrain, sl::Terrain & cost_terrain, + const float grid_resolution, RobotParameters robot_parameters, + TraversabilityParameters traversability_parameters) +{ + auto square_size_cost = robot_parameters.radius / grid_resolution; + if (square_size_cost < 1) { + square_size_cost = 1; + } + + auto factor_step_ = traversability_parameters.step_weight / robot_parameters.step_max; + auto factor_slope_ = traversability_parameters.slope_weight / robot_parameters.slope_max; + auto factor_roughness_ = traversability_parameters.roughness_weight / + robot_parameters.roughness_max; + + // Update only the recent one, and manage the border ? + const float step_height_crit = robot_parameters.step_max; + + double reso_d = grid_resolution * 1.; + + sl::Timestamp ts_tmp_elevation, ts_tmp_cost; + + double a_rad = robot_parameters.radius * 1.; + int nb_cells = (2. * a_rad) / reso_d; // big agent with small grid size is heavier to compute + + const sl::float3 z_vector(0, 0, 1); + + auto chunks_idx = elevation_terrain.getAllValidChunk(); + + // for each chunk + for (auto chunk_id : chunks_idx) { + + auto & chunk_elevation = elevation_terrain.getChunk(chunk_id); + auto & layer_height = chunk_elevation.getLayer(sl::LayerName::ELEVATION); + + auto & chunk_cost = cost_terrain.getChunk(chunk_id); + + chunk_cost.getLayer(TRAVERSABILITY_COST).clear(); + chunk_cost.getLayer(OCCUPANCY).clear(); + chunk_cost.getLayer(TRAVERSABILITY_COST_STEP).clear(); + chunk_cost.getLayer(TRAVERSABILITY_COST_SLOPE).clear(); + chunk_cost.getLayer(TRAVERSABILITY_COST_ROUGHNESS).clear(); + + auto & cost_data = chunk_cost.getLayer(TRAVERSABILITY_COST).getData(); + auto & occupancy_data = chunk_cost.getLayer(OCCUPANCY).getData(); + auto & cost_step_data = chunk_cost.getLayer(TRAVERSABILITY_COST_STEP).getData(); + auto & cost_slope_data = chunk_cost.getLayer(TRAVERSABILITY_COST_SLOPE).getData(); + auto & cost_roughness_data = chunk_cost.getLayer(TRAVERSABILITY_COST_ROUGHNESS).getData(); + + auto dim = chunk_elevation.getDimension(); + const int size_ = dim.getSize() * dim.getSize(); + + auto & elevation_data = layer_height.getData(); + + unsigned int idx_tmp; + float x, y; + for (unsigned int idx_current = 0; idx_current < size_; idx_current++) { + const float ref_height = elevation_data[idx_current]; + if (std::isfinite(ref_height)) { + dim.index2x_y(idx_current, x, y); + // SLOPE + std::vector normals_tmp; + normals_tmp.reserve(nb_cells * nb_cells); + + float max_diff_height = 0; + + double x_area_min = x - a_rad; + double y_area_min = y - a_rad; + + for (int x_ = 0; x_ < nb_cells; x_++) { + float x_v = x_area_min + (x_ * reso_d); + for (int y_ = 0; y_ < nb_cells; y_++) { + float y_v = y_area_min + (y_ * reso_d); + + float curr_height; + if (dim.getIndex(x_v, y_v, idx_tmp) /*True = error*/) { + // Probably chunk edges + curr_height = elevation_terrain.readValue(sl::LayerName::ELEVATION, x_v, y_v); + } else { + curr_height = elevation_data[idx_tmp]; + } + + if (std::isfinite(curr_height)) { + normals_tmp.emplace_back(x_v, y_v, curr_height); + max_diff_height = std::max(max_diff_height, fabsf32(curr_height - ref_height)); + } + } + } + + sl::float3 normal, centroid, eigen_values; + plane::compute_pca(normals_tmp, normal, centroid, eigen_values); + + float roughness = 0, slope = 0, step = 0, cost; + + if (max_diff_height > step_height_crit) { + step = max_diff_height; + } + + if (normals_tmp.size() >= 3) { // minimum points + float norm_len = sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z); + if (norm_len > 0.f) { + float cos_angle = std::clamp( + sl::float3::dot(normal, z_vector) / norm_len, + -1.0f, 1.0f); + slope = acos(cos_angle) * 57.295779513; // the norm of z_vector is 1 + } + + } + if (slope > 90) { + slope = 180.f - slope; + } + + roughness = sqrt(eigen_values.z); // Standard deviation of fitted plane + + cost = clamp( + (roughness * factor_roughness_ + slope * factor_slope_ + step * factor_step_) * 0.3f, + 0.f, 1.f); + cost_data[idx_current] = cost; + occupancy_data[idx_current] = + (cost > traversability_parameters.occupancy_threshold) ? OCCUPIED_CELL : FREE_CELL; + if (slope == 0) { + slope = INVALID_CELL_DATA; + } + cost_slope_data[idx_current] = slope; + cost_step_data[idx_current] = step; + cost_roughness_data[idx_current] = roughness; + } else { + occupancy_data[idx_current] = UNKNOWN_CELL; + } + } + } +} + +static const sl::float3 clr_a(244, 242, 246); +static const sl::float3 clr_b(0, 0, 0); + +// generate a linear ColorMap to match ogl interpol +inline sl::uchar3 getColorMap(float value) +{ + auto new_clr = clr_a * value + clr_b * (1.f - value); + return sl::uchar3(new_clr.b, new_clr.g, new_clr.r); +} + +void normalization(sl::Terrain & cost_terrain, sl::LayerName layer, sl::Mat & view) +{ + sl::Mat cost; + auto cost_mat = cost_terrain.retrieveView(cost, sl::MAT_TYPE::F32_C1, layer); + auto cost_res = cost.getResolution(); + view.alloc(cost_res, sl::MAT_TYPE::U8_C3); + + for (int y = 0; y < cost_res.height; y++) { + + auto ptr_cost = cost.getPtr() + y * cost.getStep(); + auto ptr_view = view.getPtr() + y * view.getStep(); + + for (int x = 0; x < cost_res.width; x++) { + float cost = ptr_cost[x]; + if (std::isfinite(cost)) { + ptr_view[x] = getColorMap(cost); + } else { + ptr_view[x] = sl::uchar3(22, 22, 22); + } + } + } +} +} +} diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_bodytrk.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_bodytrk.cpp new file mode 100644 index 0000000000..abb9ebb2c2 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_bodytrk.cpp @@ -0,0 +1,430 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zed_camera_component.hpp" +#include "sl_logging.hpp" +#include "sl_tools.hpp" + +namespace stereolabs +{ +void ZedCamera::getBodyTrkParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== Body Track. parameters ==="); + if (sl_tools::isZED(mCamUserModel)) { + RCLCPP_WARN( + get_logger(), + "!!! Body Tracking parameters are not used with ZED!!!"); + return; + } + + sl_tools::getParam( + shared_from_this(), "body_tracking.bt_enabled", + mBodyTrkEnabled, mBodyTrkEnabled, + " * Body Track. enabled: "); + + sl_tools::getEnumParam( + shared_from_this(), "body_tracking.model", "HUMAN_BODY_FAST", + sl::BODY_TRACKING_MODEL::HUMAN_BODY_FAST, + sl::BODY_TRACKING_MODEL::LAST, mBodyTrkModel, + " * Body Track. model: "); + + sl_tools::getEnumParam( + shared_from_this(), "body_tracking.body_format", "BODY_70", + sl::BODY_FORMAT::BODY_18, + sl::BODY_FORMAT::LAST, mBodyTrkFmt, + " * Body Track. format: "); + + sl_tools::getParam( + shared_from_this(), + "body_tracking.allow_reduced_precision_inference", + mBodyTrkReducedPrecision, mBodyTrkReducedPrecision, + " * Body Track. allow reduced precision: "); + + sl_tools::getParam( + shared_from_this(), "body_tracking.max_range", + mBodyTrkMaxRange, mBodyTrkMaxRange, + " * Body Track. maximum range [m]: ", false, 0.1, 40.0); + + sl_tools::getEnumParam( + shared_from_this(), "body_tracking.body_kp_selection", "FULL", + sl::BODY_KEYPOINTS_SELECTION::FULL, + sl::BODY_KEYPOINTS_SELECTION::LAST, mBodyTrkKpSelection, + " * Body Track. KP selection: "); + + sl_tools::getParam( + shared_from_this(), "body_tracking.enable_body_fitting", + mBodyTrkFitting, mBodyTrkFitting, " * Body fitting: "); + + sl_tools::getParam( + shared_from_this(), "body_tracking.enable_tracking", + mBodyTrkEnableTracking, mBodyTrkEnableTracking, + " * Body joints tracking: "); + + sl_tools::getParam( + shared_from_this(), "body_tracking.prediction_timeout_s", + mBodyTrkPredTimeout, mBodyTrkPredTimeout, + " * Body Track. prediction timeout [sec]: ", false, 0.0, 300.0); + + sl_tools::getParam( + shared_from_this(), "body_tracking.confidence_threshold", + mBodyTrkConfThresh, mBodyTrkConfThresh, + " * Body Track. confidence thresh.: ", true, 0.0, 100.0); + + sl_tools::getParam( + shared_from_this(), + "body_tracking.minimum_keypoints_threshold", mBodyTrkMinKp, + mBodyTrkMinKp, " * Body Track. min. KP thresh.: ", true, 0, 38); +} + +bool ZedCamera::handleBodyTrkDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + DEBUG_BT("handleBodyTrkDynamicParams"); + + if (param.get_name() == "body_tracking.confidence_threshold") { + rclcpp::ParameterType correctType = + rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + double val = param.as_double(); + + if ((val < 0.0) || (val >= 100.0)) { + result.successful = false; + result.reason = + param.get_name() + + " must be positive double value in the range [0.0,100.0["; + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mBodyTrkConfThresh = val; + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" << param.get_name() + << "' correctly set to " << val); + } else if (param.get_name() == + "body_tracking.minimum_keypoints_threshold") + { + rclcpp::ParameterType correctType = + rclcpp::ParameterType::PARAMETER_INTEGER; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange(param, mBodyTrkMinKp, 0, 38, result, get_logger())) { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" << param.get_name() + << "' correctly set to " + << mBodyTrkMinKp); + } + + mBodyTrkRtParamsDirty = true; + return true; +} + +bool ZedCamera::startBodyTracking() +{ + DEBUG_BT("startBodyTracking"); + + if (!sl_tools::isObjDetAvailable(mCamRealModel)) { + RCLCPP_ERROR( + get_logger(), + "Body Tracking not started. The camera model does not support " + "it with the current version " + "of the SDK"); + return false; + } + + DEBUG_BT("Body Tracking available"); + + if (mDepthDisabled) { + RCLCPP_WARN( + get_logger(), + "Cannot start Body Tracking if Depth processing is disabled"); + return false; + } + + if (!mBodyTrkEnabled) { + DEBUG_BT("Body Tracking not enabled -> NOT STARTING"); + return false; + } + + if (!mCamera2BaseTransfValid || !mSensor2CameraTransfValid || + !mSensor2BaseTransfValid) + { + DEBUG_BT( + "Tracking transforms not yet ready, Body Tracking starting postponed"); + return false; + } + + RCLCPP_INFO(get_logger(), "=== Starting Body Tracking ==="); + + sl::BodyTrackingParameters bt_p; + bt_p.allow_reduced_precision_inference = mBodyTrkReducedPrecision; + bt_p.body_format = mBodyTrkFmt; + bt_p.body_selection = mBodyTrkKpSelection; + bt_p.detection_model = mBodyTrkModel; + bt_p.enable_body_fitting = mBodyTrkFitting; + bt_p.enable_segmentation = false; + bt_p.enable_tracking = mBodyTrkEnableTracking; + bt_p.max_range = mBodyTrkMaxRange; + bt_p.prediction_timeout_s = mBodyTrkPredTimeout; + + sl::ERROR_CODE btError = mZed->enableBodyTracking(bt_p); + + if (btError != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Body Tracking error: " << sl::toString(btError)); + + mBodyTrkRunning = false; + return false; + } + + DEBUG_BT("Body Tracking enabled"); + + if (!mPubBodyTrk) { + mPubBodyTrk = create_publisher( + mBodyTrkTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + "Advertised on topic " << mPubBodyTrk->get_topic_name()); + } + + DEBUG_BT("Body Tracking publisher created"); + + mBodyTrkRunning = true; + return true; +} + +void ZedCamera::stopBodyTracking() +{ + if (mBodyTrkRunning) { + RCLCPP_INFO(get_logger(), "=== Stopping Body Tracking ==="); + mBodyTrkRunning = false; + mBodyTrkEnabled = false; + mZed->disableBodyTracking(); + + // ----> Send an empty message to indicate that no more objects are tracked + // (e.g clean RVIZ2) + auto objMsg = std::make_unique(); + + objMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + objMsg->header.frame_id = mLeftCamFrameId; + + objMsg->objects.clear(); + + DEBUG_STREAM_OD( + "Publishing EMPTY OBJ message " + << mPubBodyTrk->get_topic_name()); + try { + if (mPubBodyTrk) {mPubBodyTrk->publish(std::move(objMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + // <---- Send an empty message to indicate that no more objects are tracked + // (e.g clean RVIZ2) + } +} + +void ZedCamera::processBodies(rclcpp::Time t) +{ + // DEBUG_BT("processBodies"); + + size_t bt_sub_count = 0; + + try { + if (mPubBodyTrk) {bt_sub_count = count_subscribers(mPubBodyTrk->get_topic_name());} + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_OD("processBodies: Exception while counting subscribers"); + return; + } + + if (bt_sub_count < 1) { + mBodyTrkSubscribed = false; + return; + } + + sl_tools::StopWatch btElabTimer(get_clock()); + + mBodyTrkSubscribed = true; + + // ----> Update runtime parameters only when changed + if (mBodyTrkRtParamsDirty) { + sl::BodyTrackingRuntimeParameters bt_params_rt; + bt_params_rt.detection_confidence_threshold = mBodyTrkConfThresh; + bt_params_rt.minimum_keypoints_threshold = mBodyTrkMinKp; + mZed->setBodyTrackingRuntimeParameters(bt_params_rt); + mBodyTrkRtParamsDirty = false; + } + // <---- Update runtime parameters only when changed + + sl::Bodies bodies; + sl::ERROR_CODE btRes = + mZed->retrieveBodies(bodies); + + if (btRes != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Body Tracking error: " << sl::toString(btRes)); + return; + } + + if (!bodies.is_new) { // Async body tracking. Update data only if new + // detection is available + DEBUG_BT("No new bodies detected"); + return; + } + + size_t bodyCount = bodies.body_list.size(); + + DEBUG_STREAM_BT("Detected " << bodyCount << " bodies"); + + auto bodyMsg = std::make_unique(); + + bodyMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + bodyMsg->header.frame_id = mLeftCamFrameId; + + bodyMsg->objects.resize(bodyCount); + + size_t idx = 0; + for (const auto & body : bodies.body_list) { + std::string label = "Body_"; + label += std::to_string(body.id); + DEBUG_STREAM_BT("Processing body: " << label); + bodyMsg->objects[idx].label = sl::String(label.c_str()); + bodyMsg->objects[idx].sublabel = ""; + bodyMsg->objects[idx].label_id = body.id; + bodyMsg->objects[idx].confidence = body.confidence; + DEBUG_BT(" - Info OK"); + + memcpy( + &(bodyMsg->objects[idx].position[0]), &(body.position[0]), + 3 * sizeof(float)); + memcpy( + &(bodyMsg->objects[idx].position_covariance[0]), + &(body.position_covariance[0]), 6 * sizeof(float)); + memcpy( + &(bodyMsg->objects[idx].velocity[0]), &(body.velocity[0]), + 3 * sizeof(float)); + DEBUG_BT(" - Pos/Cov/Speed OK"); + + bodyMsg->objects[idx].tracking_available = mBodyTrkEnableTracking; + bodyMsg->objects[idx].tracking_state = + static_cast(body.tracking_state); + bodyMsg->objects[idx].action_state = + static_cast(body.action_state); + DEBUG_BT(" - Status OK"); + + if (body.bounding_box_2d.size() == 4) { + memcpy( + &(bodyMsg->objects[idx].bounding_box_2d.corners[0]), + &(body.bounding_box_2d[0]), 8 * sizeof(unsigned int)); + } + DEBUG_BT(" - BBox 2D OK"); + if (body.bounding_box.size() == 8) { + memcpy( + &(bodyMsg->objects[idx].bounding_box_3d.corners[0]), + &(body.bounding_box[0]), 24 * sizeof(float)); + } + DEBUG_BT(" - BBox 3D OK"); + + memcpy( + &(bodyMsg->objects[idx].dimensions_3d[0]), &(body.dimensions[0]), + 3 * sizeof(float)); + DEBUG_BT(" - Dims OK"); + + bodyMsg->objects[idx].body_format = static_cast(mBodyTrkFmt); + + if (body.head_bounding_box_2d.size() == 4) { + memcpy( + &(bodyMsg->objects[idx].head_bounding_box_2d.corners[0]), + &(body.head_bounding_box_2d[0]), 8 * sizeof(unsigned int)); + } + if (body.head_bounding_box.size() == 8) { + memcpy( + &(bodyMsg->objects[idx].head_bounding_box_3d.corners[0]), + &(body.head_bounding_box[0]), 24 * sizeof(float)); + } + + memcpy( + &(bodyMsg->objects[idx].head_position[0]), + &(body.head_position[0]), 3 * sizeof(float)); + + bodyMsg->objects[idx].skeleton_available = true; + + uint8_t kp_size = body.keypoint_2d.size(); + uint8_t kp_size_3d = body.keypoint.size(); + DEBUG_STREAM_BT(" * Skeleton KP: " << static_cast(kp_size)); + if (kp_size <= 70) { + memcpy( + &(bodyMsg->objects[idx].skeleton_2d.keypoints[0]), + &(body.keypoint_2d[0]), 2 * kp_size * sizeof(float)); + + uint8_t kp_copy = std::min(kp_size, kp_size_3d); + memcpy( + &(bodyMsg->objects[idx].skeleton_3d.keypoints[0]), + &(body.keypoint[0]), 3 * kp_copy * sizeof(float)); + } + + // ---------------------------------- + // at the end of the loop + + // TODO(Walter) Add support for + // body.global_root_orientation; + // body.local_orientation_per_joint; + // body.local_orientation_per_joint; + + idx++; + } + + DEBUG_STREAM_OD("Publishing BODY TRK message"); + try { + if (mPubBodyTrk) {mPubBodyTrk->publish(std::move(bodyMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + + // ----> Diagnostic information update + mBodyTrkElabMean_sec->addValue(btElabTimer.toc()); + mBodyTrkPeriodMean_sec->addValue(mBtFreqTimer.toc()); + mBtFreqTimer.tic(); + // <---- Diagnostic information update +} + +} // namespace stereolabs diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_main.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_main.cpp new file mode 100644 index 0000000000..05def07296 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_main.cpp @@ -0,0 +1,10032 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zed_camera_component.hpp" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "sl_logging.hpp" + +#ifdef FOUND_HUMBLE +#include +#elif defined FOUND_IRON +#include +#elif defined FOUND_JAZZY +#include +#elif defined FOUND_ROLLING +#include +#elif defined FOUND_FOXY +#include +#else +#error Unsupported ROS 2 distro +#endif + +#include + +#include "sl_tools.hpp" + +using namespace std::chrono_literals; +using namespace std::placeholders; + +// Used for simulation data input +#define ZED_SDK_PORT 30000 + +namespace stereolabs +{ + +ZedCamera::ZedCamera(const rclcpp::NodeOptions & options) +: Node("zed_node", options), + mDepthDisabled(false), // 530 + mStreamingServerRequired(false), // 647 + mQos(QOS_QUEUE_SIZE), // 693 + mThreadStop(false), // 954 + mNodeDeinitialized(false), // 955 + mStreamingServerRunning(false), // 1020 + mUptimer(get_clock()), // 1046 + mDiagUpdater(this), // 1075 + mImuTfFreqTimer(get_clock()), // 1077 + mGrabFreqTimer(get_clock()), // 1078 + mImuFreqTimer(get_clock()), // 1079 + mBaroFreqTimer(get_clock()), // 1080 + mMagFreqTimer(get_clock()), // 1081 + mOdomFreqTimer(get_clock()), // 1082 + mPoseFreqTimer(get_clock()), // 1083 + mPcPubFreqTimer(get_clock()), // 1084 + mVdPubFreqTimer(get_clock()), // 1085 + mSensPubFreqTimer(get_clock()), // 1086 + mOdFreqTimer(get_clock()), // 1087 + mBtFreqTimer(get_clock()), // 1088 + mPcFreqTimer(get_clock()), // 1089 + mGnssFixFreqTimer(get_clock()), // 1090 + mFrameTimestamp(TIMEZERO_ROS), // 1097 + mGnssTimestamp(TIMEZERO_ROS), // 1098 + mLastTs_imu(TIMEZERO_ROS), // 1099 + mLastTs_baro(TIMEZERO_ROS), // 1100 + mLastTs_mag(TIMEZERO_ROS), // 1101 + mLastTs_odom(TIMEZERO_ROS), // 1102 + mLastTs_pose(TIMEZERO_ROS), // 1103 + mLastTs_pc(TIMEZERO_ROS), // 1104 + mPrevTs_pc(TIMEZERO_ROS), // 1105 + mLastClock(TIMEZERO_ROS), // 1107 + mSetSvoFrameCheckTimer(get_clock()) // 1136 +{ + try { + mUsingIPC = options.use_intra_process_comms(); + + RCLCPP_INFO(get_logger(), "================================"); + RCLCPP_INFO(get_logger(), " ZED Camera Component "); + RCLCPP_INFO(get_logger(), "================================"); + RCLCPP_INFO(get_logger(), " * IPC: %s", mUsingIPC ? "enabled" : "disabled"); + + auto context = options.context(); + + rclcpp::contexts::get_global_default_context()->is_valid(); + + if (!rclcpp::contexts::get_global_default_context() || + !rclcpp::contexts::get_global_default_context()->is_valid()) + { + RCLCPP_ERROR(get_logger(), "Global context is null!"); + exit(EXIT_FAILURE); + } + + if (!context || !context->is_valid()) { + RCLCPP_ERROR(get_logger(), "Node context is null!"); + exit(EXIT_FAILURE); + } + + // Set the name of the main thread for easier identification in + // system monitors + pthread_setname_np(pthread_self(), (get_name() + std::string("_main")).c_str()); + + if (((ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < + (SDK_MAJOR_MIN_SUPP * 10 + SDK_MINOR_MIN_SUPP)) || + ((ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) > + (SDK_MAJOR_MAX_SUPP * 10 + SDK_MINOR_MAX_SUPP))) + { + RCLCPP_ERROR_STREAM( + get_logger(), + "This version of the ZED ROS2 wrapper is designed to work with ZED SDK " + "v" << static_cast(SDK_MAJOR_MIN_SUPP) + << "." << static_cast(SDK_MINOR_MIN_SUPP) << " or newer up to v" << + static_cast(SDK_MAJOR_MAX_SUPP) << "." << static_cast(SDK_MINOR_MAX_SUPP) << + "."); + RCLCPP_INFO_STREAM( + get_logger(), "* Detected SDK v" + << ZED_SDK_MAJOR_VERSION << "." + << ZED_SDK_MINOR_VERSION << "." + << ZED_SDK_PATCH_VERSION << "-" + << ZED_SDK_BUILD_ID); + RCLCPP_INFO(get_logger(), "Node stopped. Press Ctrl+C to exit."); + exit(EXIT_FAILURE); + } + + #if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 50 + sl::setEnvironmentVariable("ZED_SDK_DISABLE_PROGRESS_BAR_LOG", "1"); + #endif + + // ----> Start a "one shot timer" to initialize the node and make `shared_from_this` available + DEBUG_COMM("Creating one-shot initialization timer..."); + mInitTimer = create_wall_timer( + std::chrono::milliseconds(50), + std::bind(&ZedCamera::initNode, this)); + // <---- Start a "one shot timer" to initialize the node and make `shared_from_this` available + + DEBUG_COMM("Waiting for node initialization..."); + } catch (const std::exception & e) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Exception during ZedCamera component initialization: " << e.what()); + } catch (...) { + RCLCPP_ERROR( + get_logger(), + "Unknown exception during ZedCamera component initialization"); + } +} + +void ZedCamera::initNode() +{ + RCLCPP_INFO(get_logger(), " * namespace: %s", get_namespace()); + RCLCPP_INFO(get_logger(), " * node name: %s", get_name()); + RCLCPP_INFO(get_logger(), "================================"); + + RCLCPP_INFO(get_logger(), "Starting node initialization..."); + + // Stop the timer for "one shot" initialization + mInitTimer->cancel(); + + // ----> Publishers/Subscribers options +#ifndef FOUND_FOXY + mPubOpt.qos_overriding_options = + rclcpp::QosOverridingOptions::with_default_policies(); + mSubOpt.qos_overriding_options = + rclcpp::QosOverridingOptions::with_default_policies(); +#endif + // <---- Publishers/Subscribers options + + // Parameters initialization + initParameters(); + + // ----> Diagnostic initialization + std::string info = sl::toString(mCamUserModel).c_str(); + mDiagUpdater.add( + info, this, + &ZedCamera::callback_updateDiagnostic); + std::string hw_id = std::string("Stereolabs camera: ") + mCameraName; + mDiagUpdater.setHardwareID(hw_id); + // <---- Diagnostic initialization + + // Services initialization + initServices(); + + // ----> Start camera + if (!startCamera()) { + exit(EXIT_FAILURE); + } + // <---- Start camera + + // Callback when the node is destroyed + // This is used to stop the camera when the node is destroyed + // and to stop the timers + + // Close camera callback before shutdown + using rclcpp::contexts::get_global_default_context; + get_global_default_context()->add_pre_shutdown_callback( + [this]() { + DEBUG_COMM("ZED Component is shutting down"); + deInitNode(); + DEBUG_COMM("ZED Component is shutting down - done"); + }); + + // Dynamic parameters callback + mParamChangeCallbackHandle = add_on_set_parameters_callback( + std::bind(&ZedCamera::callback_dynamicParamChange, this, _1)); +} + +void ZedCamera::deInitNode() +{ + if (mNodeDeinitialized) { + return; + } + mNodeDeinitialized = true; + + DEBUG_COMM("De-initializing ZED Component"); + + // ----> Stop subscribers + DEBUG_COMM("Stopping subscribers"); + mClickedPtSub.reset(); + mGnssFixSub.reset(); + mClockSub.reset(); + DEBUG_COMM("... subscribers stopped"); + // <---- Stop subscribers + + if (mObjDetRunning) { + DEBUG_COMM("Stopping Object Detection"); + std::lock_guard lock(mObjDetMutex); + stopObjDetect(); + DEBUG_COMM("... Object Detection stopped"); + } + + if (mBodyTrkRunning) { + DEBUG_COMM("Stopping Body Tracking"); + std::lock_guard lock(mBodyTrkMutex); + stopBodyTracking(); + DEBUG_COMM("... Body Tracking stopped"); + } + + if (mSpatialMappingRunning) { + DEBUG_COMM("Stopping 3D Mapping"); + std::lock_guard lock(mMappingMutex); + stop3dMapping(); + DEBUG_COMM("... 3D Mapping stopped"); + } + + if (mPathTimer) { + DEBUG_COMM("Stopping path timer"); + mPathTimer->cancel(); + DEBUG_COMM("... path timer stopped"); + } + + if (mFusedPcTimer) { + DEBUG_COMM("Stopping fused cloud timer"); + mFusedPcTimer->cancel(); + DEBUG_COMM("... fused cloud timer stopped"); + } + + if (mTempPubTimer) { + DEBUG_COMM("Stopping temperatures timer"); + mTempPubTimer->cancel(); + DEBUG_COMM("... temperatures timer stopped"); + } + + // ----> Verify that all the threads are not active + DEBUG_COMM("Stopping running threads"); + if (!mThreadStop) { + mThreadStop = true; + } + + DEBUG_COMM("Waiting for sensors thread..."); + try { + if (mSensThread.joinable()) { + mSensThread.join(); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Sensors thread joining exception: " << e.what()); + } + DEBUG_COMM("... sensors thread stopped"); + + DEBUG_COMM("Waiting for video/depth thread..."); + try { + if (mVdThread.joinable()) { + mVdThread.join(); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Video/Depth thread joining exception: " << e.what()); + } + DEBUG_COMM("... video/depth thread stopped"); + + DEBUG_COMM("Waiting for Point Cloud thread..."); + try { + if (mPcThread.joinable()) { + mPcThread.join(); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Pointcloud thread joining exception: " << e.what()); + } + DEBUG_COMM("... Point Cloud thread stopped"); + + DEBUG_COMM("Waiting for grab thread..."); + try { + if (mGrabThread.joinable()) { + mGrabThread.join(); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Grab thread joining exception: " << e.what()); + } + DEBUG_COMM("... grab thread stopped"); + // <---- Verify that all the threads are not active + + DEBUG_COMM("All threads stopped. Closing camera..."); + closeCamera(); + DEBUG_COMM("... camera closed"); +} + +ZedCamera::~ZedCamera() +{ + deInitNode(); + if (_debugCommon) { + std::cout << "[ZedCamera] Destructor called" << std::endl << std::flush; + } +} + +void ZedCamera::initServices() +{ + RCLCPP_INFO(get_logger(), "=== SERVICES ==="); + + std::string srv_name; + + std::string srv_prefix = "~/"; + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is disabled + if (!mDepthDisabled || mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (!mDepthDisabled) { +#endif + + if (mPosTrackingEnabled) { + // Reset Odometry + srv_name = srv_prefix + mSrvResetOdomName; + mResetOdomSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_resetOdometry, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << mResetOdomSrv->get_service_name() + << "'"); + // Reset Pose + srv_name = srv_prefix + mSrvResetPoseName; + mResetPosTrkSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_resetPosTracking, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" + << mResetPosTrkSrv->get_service_name() << "'"); + // Set Pose + srv_name = srv_prefix + mSrvSetPoseName; + mSetPoseSrv = create_service( + srv_name, std::bind(&ZedCamera::callback_setPose, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << mSetPoseSrv->get_service_name() + << "'"); + // Save Area Memory + srv_name = srv_prefix + mSrvSaveAreaMemoryName; + mSaveAreaMemorySrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_saveAreaMemory, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" + << mSaveAreaMemorySrv->get_service_name() << "'"); + } + } + + if (!mDepthDisabled) { + // Enable Depth Processing + srv_name = srv_prefix + mSrvEnableDepthName; + mEnableDepthSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_enableDepth, this, _1, _2, _3)); + + // Enable Object Detection + srv_name = srv_prefix + mSrvEnableObjDetName; + mEnableObjDetSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_enableObjDet, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" + << mEnableObjDetSrv->get_service_name() << "'"); + + // Enable BodyTracking + srv_name = srv_prefix + mSrvEnableBodyTrkName; + mEnableBodyTrkSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_enableBodyTrk, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" + << mEnableBodyTrkSrv->get_service_name() << "'"); + + if (mPosTrackingEnabled) { + // Enable Mapping + srv_name = srv_prefix + mSrvEnableMappingName; + mEnableMappingSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_enableMapping, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" + << mEnableMappingSrv->get_service_name() << "'"); + } + } + + // Enable Streaming + srv_name = srv_prefix + mSrvEnableStreamingName; + mEnableStreamingSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_enableStreaming, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" + << mEnableStreamingSrv->get_service_name() << "'"); + + // Start SVO Recording + srv_name = srv_prefix + mSrvStartSvoRecName; + mStartSvoRecSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_startSvoRec, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << mStartSvoRecSrv->get_service_name() + << "'"); + // Stop SVO Recording + srv_name = srv_prefix + mSrvStopSvoRecName; + mStopSvoRecSrv = create_service( + srv_name, std::bind(&ZedCamera::callback_stopSvoRec, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << mStopSvoRecSrv->get_service_name() + << "'"); + + // Pause SVO (only if the realtime playing mode is disabled) + if (mSvoMode) { +#ifndef USE_SVO_REALTIME_PAUSE + if (!mSvoRealtime) { +#endif + srv_name = srv_prefix + mSrvToggleSvoPauseName; + mPauseSvoSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_pauseSvoInput, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" << mPauseSvoSrv->get_service_name() << "'"); +#ifndef USE_SVO_REALTIME_PAUSE + } +#endif + + //Set Service for SVO frame + srv_name = srv_prefix + mSrvSetSvoFrameName; + mSetSvoFrameSrv = create_service( + srv_name, + std::bind(&ZedCamera::callback_setSvoFrame, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" << mSetSvoFrameSrv->get_service_name() << "'"); + } + + // Set ROI + srv_name = srv_prefix + mSrvSetRoiName; + mSetRoiSrv = create_service( + srv_name, std::bind(&ZedCamera::callback_setRoi, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" << mSetRoiSrv->get_service_name() << "'"); + // Reset ROI + srv_name = srv_prefix + mSrvResetRoiName; + mResetRoiSrv = create_service( + srv_name, std::bind(&ZedCamera::callback_resetRoi, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" << mResetRoiSrv->get_service_name() << "'"); + + if (mPosTrackingEnabled && mGnssFusionEnabled) { + // To Latitude/Longitude + srv_name = srv_prefix + mSrvToLlName; + mToLlSrv = create_service( + srv_name, std::bind(&ZedCamera::callback_toLL, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" << mToLlSrv->get_service_name() << "'"); + // From Latitude/Longitude + srv_name = srv_prefix + mSrvFromLlName; + mFromLlSrv = create_service( + srv_name, std::bind(&ZedCamera::callback_fromLL, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on service: '" << mFromLlSrv->get_service_name() << "'"); + } +} + +std::string ZedCamera::getParam( + std::string paramName, + std::vector> & outVal) +{ + outVal.clear(); + + rcl_interfaces::msg::ParameterDescriptor descriptor; + descriptor.read_only = true; + + declare_parameter( + paramName, rclcpp::ParameterValue(std::string("[]")), + descriptor); + + std::string out_str; + + if (!get_parameter(paramName, out_str)) { + RCLCPP_WARN_STREAM( + get_logger(), + "The parameter '" + << paramName + << "' is not available or is not valid, using the default " + "value: []"); + } + + if (out_str.empty()) { + return std::string(); + } + + std::string error; + outVal = sl_tools::parseStringMultiVector_float(out_str, error); + + if (error != "") { + RCLCPP_WARN_STREAM( + get_logger(), "Error parsing " + << paramName + << " parameter: " << error.c_str()); + RCLCPP_WARN_STREAM( + get_logger(), + " " << paramName << " string was " << out_str.c_str()); + + outVal.clear(); + } + + return out_str; +} + + +void ZedCamera::initParameters() +{ + // DEBUG parameters + getDebugParams(); + + // TOPIC parameters + getTopicEnableParams(); + + // SIMULATION parameters + getSimParams(); + + // SVO parameters + getSvoParams(); + + // GENERAL parameters + getGeneralParams(); + + // VIDEO parameters + if (!mSvoMode && !mSimMode) { + getVideoParams(); + } + + // DEPTH parameters + getDepthParams(); + + // POS. TRACKING and GNSS FUSION parameters +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is + // disabled + if (!mDepthDisabled || mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (!mDepthDisabled) { +#endif + // Positional Tracking parameters + getPosTrackingParams(); + + if (mPosTrackingEnabled) { + // GNSS Fusion parameters + getGnssFusionParams(); + } else { + mGnssFusionEnabled = false; + } + } else { + mGnssFusionEnabled = false; + mPosTrackingEnabled = false; + mPublishTF = false; + mPublishOdomPose = false; + mPublishPoseCov = false; + mPublishPath = false; + } + + if (!mDepthDisabled) { + // Region of Interest parameters + getRoiParams(); + } else { + mRoyPolyParam.clear(); + mAutoRoiEnabled = false; + } + + // SENSORS parameters + if (!sl_tools::isZED(mCamUserModel)) { + getSensorsParams(); + } + + if (!mDepthDisabled && mPosTrackingEnabled) { + getMappingParams(); + } else { + mMappingEnabled = false; + } + + // AI PARAMETERS +#if ((ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 52) + if (!mDepthDisabled && mPosTrackingEnabled) { +#else + if (!mDepthDisabled) { +#endif + if (sl_tools::isObjDetAvailable(mCamUserModel)) { + getOdParams(); + getBodyTrkParams(); + } + } else { + mObjDetEnabled = false; + mBodyTrkEnabled = false; + } + + getStreamingServerParams(); + + getAdvancedParams(); +} + +std::string ZedCamera::parseRoiPoly( + const std::vector> & in_poly, + std::vector & out_poly) +{ + out_poly.clear(); + + std::string ss; + ss = "["; + + size_t poly_size = in_poly.size(); + + if (poly_size < 3) { + if (poly_size != 0) { + RCLCPP_WARN_STREAM( + get_logger(), + "A vector with " + << poly_size + << " points is not enough to create a polygon to set a Region " + "of Interest."); + return std::string(); + } + } else { + for (size_t i = 0; i < poly_size; ++i) { + if (in_poly[i].size() != 2) { + RCLCPP_WARN_STREAM( + get_logger(), "The component with index '" + << i + << "' of the ROI vector " + "has not the correct size."); + out_poly.clear(); + return std::string(); + } else if (in_poly[i][0] < 0.0 || in_poly[i][1] < 0.0 || + in_poly[i][0] > 1.0 || in_poly[i][1] > 1.0) + { + RCLCPP_WARN_STREAM( + get_logger(), "The component with index '" + << i + << "' of the ROI vector " + "is not a " + "valid normalized point: [" + << in_poly[i][0] << "," + << in_poly[i][1] << "]."); + out_poly.clear(); + return std::string(); + } else { + sl::float2 pt; + pt.x = in_poly[i][0]; + pt.y = in_poly[i][1]; + out_poly.push_back(pt); + ss += "["; + ss += std::to_string(pt.x); + ss += ","; + ss += std::to_string(pt.y); + ss += "]"; + } + + if (i != poly_size - 1) { + ss += ","; + } + } + } + ss += "]"; + + return ss; +} + +void ZedCamera::getDebugParams() +{ + rclcpp::Parameter paramVal; + + RCLCPP_INFO(get_logger(), "=== DEBUG parameters ==="); + + sl_tools::getParam( + shared_from_this(), "debug.sdk_verbose", mVerbose, + mVerbose, " * SDK Verbose: ", false, 0, 9999); + sl_tools::getParam( + shared_from_this(), "debug.use_pub_timestamps", + mUsePubTimestamps, mUsePubTimestamps, + " * Use Pub Timestamps: "); + sl_tools::getParam( + shared_from_this(), "debug.sdk_verbose_log_file", + mVerboseLogFile, mVerboseLogFile, " * SDK Verbose File: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_common", _debugCommon, + _debugCommon, " * Debug Common: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_dyn_params", + _debugDynParams, _debugDynParams, + " * Debug Dynamic Parameters: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_grab", _debugGrab, + _debugGrab, " * Debug Grab (low level): "); + sl_tools::getParam( + shared_from_this(), "debug.debug_sim", _debugSim, + _debugSim, " * Debug Simulation: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_video_depth", + _debugVideoDepth, _debugVideoDepth, + " * Debug Video/Depth: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_camera_controls", + _debugCamCtrl, _debugCamCtrl, + " * Debug Control settings: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_point_cloud", + _debugPointCloud, _debugPointCloud, + " * Debug Point Cloud: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_tf", _debugTf, _debugTf, + " * Debug TF: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_positional_tracking", + _debugPosTracking, _debugPosTracking, + " * Debug Positional Tracking: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_gnss", _debugGnss, + _debugGnss, " * Debug GNSS: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_sensors", _debugSensors, + _debugSensors, " * Debug sensors: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_mapping", _debugMapping, + _debugMapping, " * Debug Mapping: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_object_detection", + _debugObjectDet, _debugObjectDet, + " * Debug Object Detection: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_body_tracking", + _debugBodyTrk, _debugBodyTrk, " * Debug Body Tracking: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_streaming", + _debugStreaming, _debugStreaming, " * Debug Streaming: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_roi", _debugRoi, + _debugRoi, " * Debug ROI: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_nitros", _debugNitros, + _debugNitros, " * Debug Nitros: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_advanced", _debugAdvanced, + _debugAdvanced, " * Debug Advanced: "); + + mDebugMode = _debugCommon || _debugDynParams || _debugGrab || _debugSim || + _debugVideoDepth || _debugCamCtrl || _debugPointCloud || + _debugTf || _debugPosTracking || _debugGnss || _debugSensors || + _debugMapping || _debugObjectDet || _debugBodyTrk || + _debugAdvanced || _debugRoi || _debugStreaming || _debugNitros; + + if (mDebugMode) { + rcutils_ret_t res = rcutils_logging_set_logger_level( + get_logger().get_name(), RCUTILS_LOG_SEVERITY_DEBUG); + + if (res != RCUTILS_RET_OK) { + RCLCPP_INFO(get_logger(), "Error setting DEBUG level for logger"); + } else { + RCLCPP_INFO(get_logger(), " + Debug Mode enabled +"); + } + } else { + rcutils_ret_t res = rcutils_logging_set_logger_level( + get_logger().get_name(), RCUTILS_LOG_SEVERITY_INFO); + + if (res != RCUTILS_RET_OK) { + RCLCPP_INFO(get_logger(), "Error setting INFO level for logger"); + } + } + + DEBUG_STREAM_COMM( + "[ROS 2] Using RMW_IMPLEMENTATION " + << rmw_get_implementation_identifier()); + + const char * nitrosReason = "not_available"; + +#ifdef FOUND_ISAAC_ROS_NITROS + nitrosReason = "enabled"; + + sl_tools::getParam( + shared_from_this(), "debug.disable_nitros", + _nitrosDisabled, _nitrosDisabled); + + bool nitrosDisabledByParam = _nitrosDisabled; + + if (nitrosDisabledByParam) { + nitrosReason = "param_debug.disable_nitros"; + } + + if (!_nitrosDisabled && mUsingIPC) { + RCLCPP_WARN( + get_logger(), + "NITROS transport is incompatible with ROS 2 Intra-Process Communication " + "(IPC). NITROS will be disabled. To use NITROS, launch with " + "enable_ipc:=false. NITROS provides its own zero-copy transport, " + "so disabling IPC does not reduce performance."); + _nitrosDisabled = true; + nitrosReason = "auto_disabled_ipc_incompatibility"; + } + + if (nitrosDisabledByParam) { + RCLCPP_WARN( + get_logger(), + "NITROS is available, but is disabled by 'debug.disable_nitros'"); + } +#else + _nitrosDisabled = true; // Force disable NITROS if not available +#endif + + RCLCPP_DEBUG( + get_logger(), + "Transport summary: IPC=%s, NITROS=%s, reason=%s", + mUsingIPC ? "enabled" : "disabled", + _nitrosDisabled ? "disabled" : "enabled", + nitrosReason); +} + +void ZedCamera::getTopicEnableParams() +{ + RCLCPP_INFO(get_logger(), "=== TOPIC selection parameters ==="); + + // General topics + sl_tools::getParam( + shared_from_this(), "general.publish_status", mPublishStatus, + mPublishStatus, " * Publish Status: "); + + // Image topics +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + sl_tools::getParam( + shared_from_this(), "video.enable_24bit_output", + m24bitMode, m24bitMode); + if (m24bitMode) { + RCLCPP_INFO(get_logger(), " * Image format: BGR 24-bit"); + } else { + RCLCPP_INFO(get_logger(), " * Image format: BGRA 32-bit"); + } +#endif + sl_tools::getParam( + shared_from_this(), "video.publish_left_right", mPublishImgLeftRight, + mPublishImgLeftRight, " * Publish Left/Right images: "); + sl_tools::getParam( + shared_from_this(), "video.publish_raw", mPublishImgRaw, + mPublishImgRaw, " * Publish Raw images: "); + sl_tools::getParam( + shared_from_this(), "video.publish_gray", mPublishImgGray, + mPublishImgGray, " * Publish Gray images: "); + sl_tools::getParam( + shared_from_this(), "video.publish_rgb", mPublishImgRgb, + mPublishImgRgb, " * Publish RGB image: "); + sl_tools::getParam( + shared_from_this(), "video.publish_stereo", mPublishImgStereo, + mPublishImgStereo, " * Publish Stereo image: "); + + // Region of Interest topics + sl_tools::getParam( + shared_from_this(), "region_of_interest.publish_roi_mask", mPublishImgRoiMask, + mPublishImgRoiMask, " * Publish ROI Mask image: "); + + // Depth topics + sl_tools::getParam( + shared_from_this(), "depth.publish_depth_map", mPublishDepthMap, + mPublishDepthMap, " * Publish Depth Map: "); + sl_tools::getParam( + shared_from_this(), "depth.publish_depth_info", mPublishDepthInfo, + mPublishDepthInfo, " * Publish Depth Info: "); + sl_tools::getParam( + shared_from_this(), "depth.publish_point_cloud", mPublishPointcloud, + mPublishPointcloud, " * Publish Point Cloud: "); + sl_tools::getParam( + shared_from_this(), "depth.publish_depth_confidence", mPublishConfidence, + mPublishConfidence, " * Publish Depth Confidence: "); + sl_tools::getParam( + shared_from_this(), "depth.publish_disparity", mPublishDisparity, + mPublishDisparity, " * Publish Disparity: "); + + // Sensor topics + sl_tools::getParam( + shared_from_this(), "sensors.publish_imu", mPublishSensImu, + mPublishSensImu, " * Publish IMU: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_imu_raw", mPublishSensImuRaw, + mPublishSensImuRaw, " * Publish IMU Raw: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_cam_imu_transf", mPublishSensImuTransf, + mPublishSensImuTransf, " * Publish LeftCam/IMU Transf.: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_mag", mPublishSensMag, + mPublishSensMag, " * Publish Magnetometer: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_baro", mPublishSensBaro, + mPublishSensBaro, " * Publish Barometer: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_temp", mPublishSensTemp, + mPublishSensTemp, " * Publish Temperature: "); + + // Localization topics + sl_tools::getParam( + shared_from_this(), "pos_tracking.publish_odom_pose", mPublishOdomPose, + mPublishOdomPose, " * Publish Odometry/Pose: "); + sl_tools::getParam( + shared_from_this(), "pos_tracking.publish_pose_cov", mPublishPoseCov, + mPublishPoseCov, " * Publish Pose with Covariance: "); + sl_tools::getParam( + shared_from_this(), "pos_tracking.publish_cam_path", mPublishPath, + mPublishPath, " * Publish Camera Path: "); + + // Mapping topics + sl_tools::getParam( + shared_from_this(), "mapping.publish_det_plane", mPublishDetPlane, + mPublishDetPlane, " * Publish Detection Plane: "); +} + +void ZedCamera::getSimParams() +{ + // SIMULATION active? + sl_tools::getParam( + shared_from_this(), "simulation.sim_enabled", mSimMode, + mSimMode); + + if (!get_parameter("use_sim_time", mUseSimTime)) { + RCLCPP_WARN( + get_logger(), + "The parameter 'use_sim_time' is not available or is not " + "valid, using the default value."); + } + + if (mSimMode) { + RCLCPP_INFO(get_logger(), " === SIMULATION MODE ACTIVE ==="); + sl_tools::getParam( + shared_from_this(), "simulation.sim_address", mSimAddr, + mSimAddr, " * Sim. server address: "); + sl_tools::getParam( + shared_from_this(), "simulation.sim_port", mSimPort, + mSimPort, " * Sim. server port: "); + + RCLCPP_INFO_STREAM( + get_logger(), + " * Use Sim Time: " << (mUseSimTime ? "TRUE" : "FALSE")); + } else if (mUseSimTime) { + RCLCPP_WARN( + get_logger(), + "The parameter 'use_sim_time' is set to 'true', but simulation " + "mode is not enabled. UNPREDICTABLE BEHAVIORS EXPECTED."); + } +} + +void ZedCamera::getGeneralParams() +{ + rclcpp::Parameter paramVal; + + mStreamMode = false; + if (!mSvoMode) { + RCLCPP_INFO(get_logger(), "=== LOCAL STREAMING parameters ==="); + sl_tools::getParam( + shared_from_this(), "stream.stream_address", + std::string(), mStreamAddr); + if (mStreamAddr != "") { + mStreamMode = true; + sl_tools::getParam( + shared_from_this(), "stream.stream_port", mStreamPort, + mStreamPort); + RCLCPP_INFO_STREAM( + get_logger(), " * Local stream input: " << mStreamAddr << ":" << mStreamPort); + } else { + RCLCPP_INFO(get_logger(), " * Local stream input: DISABLED"); + } + } + + RCLCPP_INFO(get_logger(), "=== GENERAL parameters ==="); + + std::string camera_model = "zed2i"; + sl_tools::getParam( + shared_from_this(), "general.camera_model", camera_model, + camera_model); + if (camera_model == "zed") { + mCamUserModel = sl::MODEL::ZED; + } else if (camera_model == "zedm") { + mCamUserModel = sl::MODEL::ZED_M; + } else if (camera_model == "zed2") { + mCamUserModel = sl::MODEL::ZED2; + } else if (camera_model == "zed2i") { + mCamUserModel = sl::MODEL::ZED2i; + } else if (camera_model == "zedx") { + mCamUserModel = sl::MODEL::ZED_X; + if (mSvoMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing an SVO for " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (mStreamMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing a network stream from a " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (mSimMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Simulating a " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (!IS_JETSON) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Camera model " << sl::toString(mCamUserModel).c_str() + << " is available only with NVIDIA Jetson devices."); + exit(EXIT_FAILURE); + } + } else if (camera_model == "zedxm") { + mCamUserModel = sl::MODEL::ZED_XM; + if (mSvoMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing an SVO for " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (mStreamMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing a network stream from a " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (mSimMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Simulating a " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (!IS_JETSON) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Camera model " << sl::toString(mCamUserModel).c_str() + << " is available only with NVIDIA Jetson devices."); + exit(EXIT_FAILURE); + } + } else if (camera_model == "virtual") { + mCamUserModel = sl::MODEL::VIRTUAL_ZED_X; + + if (mSvoMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing an SVO for " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (mStreamMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing a network stream from a " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (mSimMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Simulating a " + << sl::toString(mCamUserModel) + << " camera model."); + } else if (!IS_JETSON) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Camera model " << sl::toString(mCamUserModel).c_str() + << " is available only with NVIDIA Jetson devices."); + exit(EXIT_FAILURE); + } + } else { + RCLCPP_ERROR_STREAM( + get_logger(), + "Camera model not valid in parameter values: " << camera_model); + } + RCLCPP_INFO_STREAM( + get_logger(), " * Camera model: " << camera_model << " - " + << mCamUserModel); + + sl_tools::getParam( + shared_from_this(), "general.camera_name", mCameraName, + mCameraName, " * Camera name: "); + + if (!mSvoMode) { + if (mCamUserModel == sl::MODEL::VIRTUAL_ZED_X) { + std::string array_param = "[]"; + sl_tools::getParam( + shared_from_this(), "general.virtual_serial_numbers", + array_param, array_param, + " * Virtual Camera SNs: ", false); + + std::string error; + auto serials = sl_tools::parseStringVector_int(array_param, error); + if (serials.size() == 2) { + mCamVirtualSerialNumbers = serials; + } + + array_param = "[]"; + sl_tools::getParam( + shared_from_this(), "general.virtual_camera_ids", + array_param, array_param, + " * Virtual Camera IDs: ", false); + + auto ids = sl_tools::parseStringVector_int(array_param, error); + if (ids.size() == 2) { + mCamVirtualCameraIds = ids; + } + + // With a live virtual stereo camera at least one of "general.virtual_camera_ids" and "general.virtual_serial_numbers" + // must contain two valid values + if (ids.size() != 2 && serials.size() != 2) { + RCLCPP_ERROR( + get_logger(), + "With a Virtual Stereo Camera setup, one of 'general.virtual_serial_numbers' " + "or 'general.virtual_camera_ids' parameters must contain two " + "valid values (Left and Right camera identification)."); + exit(EXIT_FAILURE); + } + } else { + sl_tools::getParam( + shared_from_this(), "general.serial_number", + mCamSerialNumber, mCamSerialNumber, + " * Camera SN: ", false, 0); + sl_tools::getParam( + shared_from_this(), "general.camera_id", mCamId, + mCamId, " * Camera ID: ", false, -1, 256); + } + sl_tools::getParam( + shared_from_this(), "general.camera_timeout_sec", + mCamTimeoutSec, mCamTimeoutSec, + " * Camera timeout [sec]: ", false, 0, 9999); + sl_tools::getParam( + shared_from_this(), "general.camera_max_reconnect", + mMaxReconnectTemp, mMaxReconnectTemp, + " * Camera reconnection temptatives: ", false, 0, 9999); + if (mSimMode) { + RCLCPP_INFO( + get_logger(), + "* [Simulation mode] Camera framerate forced to 60 Hz"); + mCamGrabFrameRate = 60; + } else { + sl_tools::getParam( + shared_from_this(), "general.grab_frame_rate", + mCamGrabFrameRate, mCamGrabFrameRate, + " * Camera framerate: ", false, 0, 120); + } + } else { + // Set it to the maximum possible frame rate to avoid problem on the next validations + // This value will be forced to the correct SVO rate after it has been opened. + mCamGrabFrameRate = 120; + } + sl_tools::getParam( + shared_from_this(), "general.gpu_id", mGpuId, mGpuId, + " * GPU ID: ", false, -1, 999); + sl_tools::getParam( + shared_from_this(), "general.async_image_retrieval", + mAsyncImageRetrieval, mAsyncImageRetrieval, + " * Asynchronous image retrieval: "); + + sl_tools::getParam( + shared_from_this(), "general.enable_image_validity_check", + mImageValidityCheck, mImageValidityCheck, + " * Image Validity Check: ", false, 0, 10); + + // TODO(walter) ADD SVO SAVE COMPRESSION PARAMETERS + + if (mSimMode) { + RCLCPP_INFO( + get_logger(), + "* [Simulation mode] Camera resolution forced to 'HD1080'"); + mCamResol = sl::RESOLUTION::HD1080; + } else { + std::string resol = "AUTO"; + sl_tools::getParam( + shared_from_this(), "general.grab_resolution", resol, + resol); + if (resol == "AUTO") { + mCamResol = sl::RESOLUTION::AUTO; + } else if (sl_tools::isZEDX(mCamUserModel)) { + if (resol == "HD1200") { + mCamResol = sl::RESOLUTION::HD1200; + } else if (resol == "HD1080") { + mCamResol = sl::RESOLUTION::HD1080; + } else if (resol == "SVGA") { + mCamResol = sl::RESOLUTION::SVGA; + } else if (resol == "HD1536") { + mCamResol = sl::RESOLUTION::HD1536; +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + } else if (resol == "XVGA") { + mCamResol = sl::RESOLUTION::XVGA; +#endif + } else { + RCLCPP_WARN( + get_logger(), + "Not valid 'general.grab_resolution' value: '%s'. Using " + "'AUTO' setting.", + resol.c_str()); + mCamResol = sl::RESOLUTION::AUTO; + } + } else { + if (resol == "HD2K") { + mCamResol = sl::RESOLUTION::HD2K; + } else if (resol == "HD1080") { + mCamResol = sl::RESOLUTION::HD1080; + } else if (resol == "HD720") { + mCamResol = sl::RESOLUTION::HD720; + } else if (resol == "VGA") { + mCamResol = sl::RESOLUTION::VGA; + } else { + RCLCPP_WARN( + get_logger(), + "Not valid 'general.grab_resolution' value: '%s'. Using " + "'AUTO' setting.", + resol.c_str()); + mCamResol = sl::RESOLUTION::AUTO; + } + } + RCLCPP_INFO_STREAM( + get_logger(), " * Camera resolution: " + << sl::toString(mCamResol).c_str()); + } + + std::string out_resol = "NATIVE"; + sl_tools::getParam( + shared_from_this(), "general.pub_resolution", out_resol, + out_resol); + if (out_resol == toString(PubRes::NATIVE)) { + mPubResolution = PubRes::NATIVE; + } else if (out_resol == toString(PubRes::CUSTOM)) { + mPubResolution = PubRes::CUSTOM; + } else { + RCLCPP_WARN( + get_logger(), + "Not valid 'general.pub_resolution' value: '%s'. Using default " + "setting instead.", + out_resol.c_str()); + out_resol = "NATIVE -> Fix the value in YAML!"; + mPubResolution = PubRes::NATIVE; + } + RCLCPP_INFO_STREAM( + get_logger(), + " * Publishing resolution: " << out_resol.c_str()); + + if (mPubResolution == PubRes::CUSTOM) { + sl_tools::getParam( + shared_from_this(), "general.pub_downscale_factor", + mCustomDownscaleFactor, mCustomDownscaleFactor, + " * Publishing downscale factor: ", false, 1.0, 5.0); + } else { + mCustomDownscaleFactor = 1.0; + } + + sl_tools::getParam( + shared_from_this(), "general.optional_opencv_calibration_file", + mOpencvCalibFile, mOpencvCalibFile, " * OpenCV custom calibration: "); + + sl_tools::getParam( + shared_from_this(), "general.self_calib", mCameraSelfCalib, + mCameraSelfCalib, " * Camera self calibration: "); + + sl_tools::getParam( + shared_from_this(), "general.camera_flip", mCameraFlip, + mCameraFlip, " * Camera flip: "); + + // Dynamic parameters + + if (mSimMode) { + RCLCPP_INFO( + get_logger(), + "* [Simulation mode] Publish framerate forced to 60 Hz"); + mVdPubRate = 60; + } + + if (mSvoMode && !mSvoRealtime) { + RCLCPP_INFO( + get_logger(), + " * [SVO mode - not realtime] Publish framerate forced to SVO Playback rate"); + mVdPubRate = 0; + } else { + sl_tools::getParam( + shared_from_this(), "general.pub_frame_rate", mVdPubRate, + mVdPubRate, " * Publish framerate [Hz]: ", true, -1.0, + static_cast(mCamGrabFrameRate)); + if (mVdPubRate <= 0.0) { + mVdPubRate = static_cast(mCamGrabFrameRate); + } + } + sl_tools::getParam( + shared_from_this(), "general.grab_compute_capping_fps", + mGrabComputeCappingFps, mGrabComputeCappingFps, + " * Grab Compute Capping FPS: ", false, 0.0, + static_cast(mCamGrabFrameRate)); +} + +void ZedCamera::getSvoParams() +{ + rclcpp::Parameter paramVal; + + RCLCPP_INFO(get_logger(), "=== SVO INPUT parameters ==="); + + sl_tools::getParam( + shared_from_this(), "svo.svo_path", std::string(), + mSvoFilepath); + if (mSvoFilepath.compare("live") == 0) { + mSvoFilepath = ""; + } + + if (mSvoFilepath == "") { + mSvoMode = false; + RCLCPP_INFO_STREAM(get_logger(), " * SVO input: DISABLED"); + } else { + RCLCPP_INFO_STREAM( + get_logger(), + " * SVO: '" << mSvoFilepath.c_str() << "'"); + mSvoMode = true; + sl_tools::getParam( + shared_from_this(), "svo.use_svo_timestamps", + mUseSvoTimestamp, mUseSvoTimestamp, + " * Use SVO timestamp: "); + if (mUseSvoTimestamp) { + sl_tools::getParam( + shared_from_this(), "svo.publish_svo_clock", + mPublishSvoClock, mPublishSvoClock, + " * Publish SVO timestamp: "); + } + + sl_tools::getParam(shared_from_this(), "svo.svo_loop", mSvoLoop, mSvoLoop); + if (mUseSvoTimestamp) { + if (mSvoLoop) { + RCLCPP_WARN( + get_logger(), + "SVO Loop is not supported when using SVO timestamps. Loop " + "playback disabled."); + mSvoLoop = false; + } + RCLCPP_INFO_STREAM( + get_logger(), + " * SVO Loop: " << (mSvoLoop ? "TRUE" : "FALSE")); + } + sl_tools::getParam( + shared_from_this(), "svo.svo_realtime", mSvoRealtime, + mSvoRealtime, " * SVO Realtime: "); + + sl_tools::getParam( + shared_from_this(), "svo.play_from_frame", + mSvoFrameStart, mSvoFrameStart, + " * SVO start frame: ", false, 0); + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + sl_tools::getParam( + shared_from_this(), "svo.decryption_key", std::string(), + mSvoDecryptionKey); +#endif + + if (!mSvoRealtime) { + sl_tools::getParam( + shared_from_this(), "svo.replay_rate", mSvoRate, + mSvoRate, " * SVO replay rate: ", true, 0.1, 5.0); + } + } +} + +void ZedCamera::getRoiParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== REGION OF INTEREST parameters ==="); + + sl_tools::getParam( + shared_from_this(), "region_of_interest.automatic_roi", + mAutoRoiEnabled, mAutoRoiEnabled, + " * Automatic ROI generation: "); + + if (mAutoRoiEnabled) { + if (mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_1) { + RCLCPP_WARN_STREAM( + get_logger(), + "Automatic ROI generation with '" + << sl::toString(mPosTrkMode) + << "' is not recommended. Please set the parameter " + "'pos_tracking.pos_tracking_mode' to 'GEN_3' for " + "improved results."); + } + + sl_tools::getParam( + shared_from_this(), "region_of_interest.depth_far_threshold_meters", + mRoiDepthFarThresh, mRoiDepthFarThresh, " * Depth far threshold [m]: "); + sl_tools::getParam( + shared_from_this(), + "region_of_interest.image_height_ratio_cutoff", + mRoiImgHeightRationCutOff, mRoiImgHeightRationCutOff, + " * Image Height Ratio Cut Off: "); + } else { + std::string parsed_str = + this->getParam("region_of_interest.manual_polygon", mRoyPolyParam); + RCLCPP_INFO_STREAM( + get_logger(), + " * Manual ROI polygon: " << parsed_str.c_str()); + } + + if (mRoyPolyParam.size() > 0 || mAutoRoiEnabled) { + mRoiModules.clear(); + bool apply = true; + + sl_tools::getParam( + shared_from_this(), "region_of_interest.apply_to_depth", + apply, apply, " * Apply to depth: "); + if (apply) { + mRoiModules.insert(sl::MODULE::DEPTH); + } + + apply = true; + sl_tools::getParam( + shared_from_this(), + "region_of_interest.apply_to_positional_tracking", apply, + apply, " * Apply to positional tracking: "); + if (apply) { + mRoiModules.insert(sl::MODULE::POSITIONAL_TRACKING); + } + + apply = true; + sl_tools::getParam( + shared_from_this(), + "region_of_interest.apply_to_object_detection", apply, + apply, " * Apply to object detection: "); + if (apply) { + mRoiModules.insert(sl::MODULE::OBJECT_DETECTION); + } + + apply = true; + sl_tools::getParam( + shared_from_this(), + "region_of_interest.apply_to_body_tracking", apply, + apply, " * Apply to body tracking: "); + if (apply) { + mRoiModules.insert(sl::MODULE::BODY_TRACKING); + } + + apply = true; + sl_tools::getParam( + shared_from_this(), + "region_of_interest.apply_to_spatial_mapping", apply, + apply, " * Apply to spatial mapping: "); + if (apply) { + mRoiModules.insert(sl::MODULE::SPATIAL_MAPPING); + } + } +} + +void ZedCamera::getSensorsParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== SENSORS STACK parameters ==="); + if (sl_tools::isZED(mCamUserModel)) { + RCLCPP_WARN( + get_logger(), + "!!! SENSORS parameters are not used with ZED !!!"); + return; + } + + sl_tools::getParam( + shared_from_this(), "sensors.publish_imu_tf", + mPublishImuTF, mPublishImuTF, + " * Broadcast IMU TF [not for ZED]: "); + + sl_tools::getParam( + shared_from_this(), "sensors.sensors_image_sync", + mSensCameraSync, mSensCameraSync, + " * Sensors Camera Sync: "); + + sl_tools::getParam( + shared_from_this(), "sensors.sensors_pub_rate", + mSensPubRate, mSensPubRate, " * Sensors publishing rate [Hz]: ", true, 1.0, 400.0); +} + +void ZedCamera::getMappingParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== Spatial Mapping parameters ==="); + + sl_tools::getParam( + shared_from_this(), "mapping.mapping_enabled", + mMappingEnabled, mMappingEnabled, + " * Spatial Mapping Enabled: "); + + sl_tools::getParam( + shared_from_this(), "mapping.resolution", mMappingRes, + mMappingRes, " * Spatial Mapping resolution [m]: "); + sl_tools::getParam( + shared_from_this(), "mapping.max_mapping_range", + mMappingRangeMax, mMappingRangeMax); + if (mMappingRangeMax == -1.0f) { + RCLCPP_INFO(get_logger(), " * 3D Max Mapping range: AUTO"); + } else { + RCLCPP_INFO_STREAM( + get_logger(), + " * 3D Max Mapping range [m]: " << mMappingRangeMax); + } + sl_tools::getParam( + shared_from_this(), "mapping.fused_pointcloud_freq", + mFusedPcPubRate, mFusedPcPubRate, + " * Map publishing rate [Hz]: ", true, -1.0, 30.0); + if (mFusedPcPubRate <= 0.0) { + mFusedPcPubRate = mPcPubRate; + } + + mClickedPtTopic = "/clicked_point"; + sl_tools::getParam( + shared_from_this(), "mapping.clicked_point_topic", + mClickedPtTopic, mClickedPtTopic, + " * Clicked point topic: "); + + sl_tools::getParam( + shared_from_this(), "mapping.pd_max_distance_threshold", + mPdMaxDistanceThreshold, mPdMaxDistanceThreshold, + " * Plane Det. Max Dist. Thresh.: ", false, 0.0, 100.0); + sl_tools::getParam( + shared_from_this(), + "mapping.pd_normal_similarity_threshold", + mPdNormalSimilarityThreshold, mPdNormalSimilarityThreshold, + " * Plane Det. Normals Sim. Thresh.: ", false, -180.0, 180.0); +} + +void ZedCamera::getPosTrackingParams() +{ + rclcpp::Parameter paramVal; + std::string paramName; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== POSITIONAL TRACKING parameters ==="); + + mBaseFrameId = mCameraName; + mBaseFrameId += "_camera_link"; + + sl_tools::getParam( + shared_from_this(), "pos_tracking.map_frame", mMapFrameId, + mMapFrameId, " * Map frame id: "); + sl_tools::getParam( + shared_from_this(), "pos_tracking.odometry_frame", + mOdomFrameId, mOdomFrameId, " * Odometry frame id: "); + + sl_tools::getParam( + shared_from_this(), "pos_tracking.pos_tracking_enabled", + mPosTrackingEnabled, mPosTrackingEnabled, + " * Positional tracking enabled: "); + + if (mPosTrackingEnabled) { + std::string pos_trk_mode_str = "AUTO"; + sl_tools::getParam( + shared_from_this(), "pos_tracking.pos_tracking_mode", + pos_trk_mode_str, pos_trk_mode_str); + bool matched = false; + bool auto_pt = false; + if (sl_tools::toUpper(pos_trk_mode_str) == "AUTO") { + // Use the SDK's own constructed default, except for 5.2.0 where + // it defaults to GEN_3 which has known issues — force GEN_1 instead +#if (ZED_SDK_MAJOR_VERSION == 5 && ZED_SDK_MINOR_VERSION == 2 && \ + ZED_SDK_PATCH_VERSION == 0) + mPosTrkMode = sl::POSITIONAL_TRACKING_MODE::GEN_1; +#else + sl::PositionalTrackingParameters defaultPtParams; + mPosTrkMode = defaultPtParams.mode; +#endif + matched = true; + auto_pt = true; + } else { + matched = sl_tools::matchSdkEnum( + pos_trk_mode_str, sl::POSITIONAL_TRACKING_MODE::GEN_1, + sl::POSITIONAL_TRACKING_MODE::LAST, mPosTrkMode); + } + if (!matched) { +#if (ZED_SDK_MAJOR_VERSION == 5 && ZED_SDK_MINOR_VERSION == 2 && \ + ZED_SDK_PATCH_VERSION == 0) + mPosTrkMode = sl::POSITIONAL_TRACKING_MODE::GEN_1; +#else + sl::PositionalTrackingParameters defaultPtParams; + mPosTrkMode = defaultPtParams.mode; +#endif + RCLCPP_WARN_STREAM( + get_logger(), + "The value of the parameter 'pos_tracking.pos_tracking_mode' is not valid: '" + << pos_trk_mode_str << "'. Using the default value."); + } + RCLCPP_INFO_STREAM( + get_logger(), " * Positional tracking mode" << (auto_pt ? " [AUTO]: " : ": ") << sl::toString( + mPosTrkMode).c_str()); + + sl_tools::getParam( + shared_from_this(), "pos_tracking.publish_tf", mPublishTF, + mPublishTF, " * Broadcast Odometry TF: "); + if (mPublishTF) { + sl_tools::getParam( + shared_from_this(), "pos_tracking.publish_map_tf", + mPublishMapTF, mPublishMapTF, " * Broadcast Pose TF: "); + } else { + mPublishMapTF = false; + } + + sl_tools::getParam( + shared_from_this(), "pos_tracking.depth_min_range", + mPosTrackDepthMinRange, mPosTrackDepthMinRange, + " * Depth minimum range: ", false, 0.0f, 40.0f); + sl_tools::getParam( + shared_from_this(), "pos_tracking.transform_time_offset", + mTfOffset, mTfOffset, " * TF timestamp offset: ", true, + -10.0, 10.0); + sl_tools::getParam( + shared_from_this(), "pos_tracking.path_pub_rate", + mPathPubRate, mPathPubRate, + " * Path publishing rate: ", true, -1.0, 120.0); + if (mPathPubRate <= 0.0) { + mPathPubRate = static_cast(mCamGrabFrameRate); + } + sl_tools::getParam( + shared_from_this(), "pos_tracking.path_max_count", + mPathMaxCount, mPathMaxCount, " * Path history lenght: ", false, -1, 10000); + + paramName = "pos_tracking.initial_base_pose"; + declare_parameter( + paramName, rclcpp::ParameterValue(mInitialBasePose), + read_only_descriptor); + if (!get_parameter(paramName, mInitialBasePose)) { + RCLCPP_WARN_STREAM( + get_logger(), + "The parameter '" + << paramName + << "' is not available or is not valid, using the default value"); + mInitialBasePose = std::vector(6, 0.0); + } + if (mInitialBasePose.size() < 6) { + RCLCPP_WARN_STREAM( + get_logger(), + "The parameter '" + << paramName + << "' must be a vector of 6 values of double type"); + mInitialBasePose = std::vector(6, 0.0); + } + RCLCPP_INFO( + get_logger(), " * Initial pose: [%g,%g,%g,%g,%g,%g,]", + mInitialBasePose[0], mInitialBasePose[1], mInitialBasePose[2], + mInitialBasePose[3], mInitialBasePose[4], mInitialBasePose[5]); + + // TODO(Walter) Fix this as soon as the `sl::Fusion` module will support loop + // closure and odometry + if (mGnssFusionEnabled) { + mAreaMemory = false; + RCLCPP_INFO(get_logger(), " * Area Memory: FALSE - Forced by GNSS usage"); + RCLCPP_INFO( + get_logger(), + " Note: loop closure (Area Memory) is disabled when using " + "GNSS fusion"); + } else { + sl_tools::getParam( + shared_from_this(), "pos_tracking.area_memory", + mAreaMemory, mAreaMemory, " * Area Memory: "); + sl_tools::getParam( + shared_from_this(), "pos_tracking.area_file_path", + mAreaMemoryFilePath, mAreaMemoryFilePath, + " * Area Memory File: "); + sl_tools::getParam( + shared_from_this(), "pos_tracking.enable_localization_only", + mLocalizationOnly, mLocalizationOnly, + " * Enable Localization Only: "); + sl_tools::getParam( + shared_from_this(), "pos_tracking.save_area_memory_on_closing", + mSaveAreaMemoryOnClosing, mSaveAreaMemoryOnClosing, + " * Save Area Memory on closing: "); + + if (mAreaMemoryFilePath.empty()) { + if (mSaveAreaMemoryOnClosing) { + RCLCPP_WARN( + get_logger(), + " * The parameter 'pos_tracking.area_file_path' is empty, " + "no Area Memory File will be saved on closing."); + mSaveAreaMemoryOnClosing = false; + } + } else { + mAreaMemoryFilePath = sl_tools::getFullFilePath(mAreaMemoryFilePath); + mAreaFileExists = std::filesystem::exists(mAreaMemoryFilePath); + + if (mAreaFileExists) { + RCLCPP_INFO_STREAM( + get_logger(), + " * Using the existing Area Memory file '" << mAreaMemoryFilePath << "'"); + if (mSaveAreaMemoryOnClosing) { + RCLCPP_INFO( + get_logger(), + " * The Area Memory file will be updated on node closing or by manually calling the `save_area_memory` service with empty parameter."); + } + } else { + RCLCPP_INFO_STREAM( + get_logger(), + " * The Area Memory file '" << mAreaMemoryFilePath << "' does not exist."); + if (mSaveAreaMemoryOnClosing) { + RCLCPP_INFO( + get_logger(), + " * The Area Memory file will be created on node closing or by manually calling the `save_area_memory` service with empty parameter."); + } + } + } + + } + sl_tools::getParam( + shared_from_this(), "pos_tracking.set_as_static", + mSetAsStatic, mSetAsStatic, " * Camera is static: "); + + sl_tools::getParam( + shared_from_this(), "pos_tracking.set_gravity_as_origin", + mSetGravityAsOrigin, mSetGravityAsOrigin, + " * Gravity as origin: "); + sl_tools::getParam( + shared_from_this(), "pos_tracking.imu_fusion", mImuFusion, + mImuFusion, " * IMU Fusion: "); + + sl_tools::getParam( + shared_from_this(), "pos_tracking.floor_alignment", + mFloorAlignment, mFloorAlignment, " * Floor Alignment: "); + + sl_tools::getParam( + shared_from_this(), + "pos_tracking.reset_odom_with_loop_closure", + mResetOdomWhenLoopClosure, mResetOdomWhenLoopClosure, + " * Reset Odometry with Loop Closure: "); + + sl_tools::getParam( + shared_from_this(), + "pos_tracking.publish_3d_landmarks", + mPublish3DLandmarks, mPublish3DLandmarks, + " * Publish 3D Landmarks: "); + + sl_tools::getParam( + shared_from_this(), + "pos_tracking.publish_lm_skip_frame", + mPublishLandmarkSkipFrame, mPublishLandmarkSkipFrame, + " * Publish Landmark Skip Frame: "); + + sl_tools::getParam( + shared_from_this(), "pos_tracking.two_d_mode", mTwoDMode, + mTwoDMode, " * 2D mode: "); + + if (mTwoDMode) { + sl_tools::getParam( + shared_from_this(), "pos_tracking.fixed_z_value", + mFixedZValue, mFixedZValue, " * Fixed Z value: "); + } + sl_tools::getParam( + shared_from_this(), + "pos_tracking.reset_pose_with_svo_loop", + mResetPoseWithSvoLoop, mResetPoseWithSvoLoop, + " * Reset pose with SVO loop: "); + } else { + mPublishTF = false; + mPublishOdomPose = false; + mPublishPoseCov = false; + mPublishPath = false; + } +} + +void ZedCamera::getGnssFusionParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== GNSS FUSION parameters ==="); + if (sl_tools::isZED(mCamUserModel)) { + RCLCPP_WARN( + get_logger(), + "!!! GNSS FUSION module cannot be enabled with ZED!!!"); + return; + } + + sl_tools::getParam( + shared_from_this(), "gnss_fusion.gnss_fusion_enabled", + mGnssFusionEnabled, mGnssFusionEnabled, + " * GNSS fusion enabled: "); + + if (mGnssFusionEnabled) { + mGnssFrameId = mCameraName + "_gnss_link"; + + sl_tools::getParam( + shared_from_this(), "gnss_fusion.gnss_fix_topic", + mGnssTopic, mGnssTopic, " * GNSS topic name: "); + sl_tools::getParam( + shared_from_this(), + "gnss_fusion.enable_reinitialization", + mGnssEnableReinitialization, mGnssEnableReinitialization, + " * GNSS Reinitialization: "); + sl_tools::getParam( + shared_from_this(), "gnss_fusion.enable_rolling_calibration", + mGnssEnableRollingCalibration, mGnssEnableRollingCalibration, + " * GNSS Rolling Calibration: "); + sl_tools::getParam( + shared_from_this(), + "gnss_fusion.enable_translation_uncertainty_target", + mGnssEnableTranslationUncertaintyTarget, + mGnssEnableTranslationUncertaintyTarget, + " * GNSS Transl. Uncert. Target: "); + sl_tools::getParam( + shared_from_this(), + "gnss_fusion.gnss_vio_reinit_threshold", + mGnssVioReinitThreshold, mGnssVioReinitThreshold, + " * GNSS VIO Reinit. Thresh.: "); + sl_tools::getParam( + shared_from_this(), "gnss_fusion.target_translation_uncertainty", + mGnssTargetTranslationUncertainty, mGnssTargetTranslationUncertainty, + " * GNSS Target Transl. Uncert.: "); + sl_tools::getParam( + shared_from_this(), "gnss_fusion.target_yaw_uncertainty", + mGnssTargetYawUncertainty, mGnssTargetYawUncertainty, + " * GNSS Target Yaw Uncert.: "); + sl_tools::getParam( + shared_from_this(), "gnss_fusion.gnss_zero_altitude", + mGnssZeroAltitude, mGnssZeroAltitude, + " * GNSS Zero Altitude: "); + + sl_tools::getParam( + shared_from_this(), "gnss_fusion.h_covariance_mul", + mGnssHcovMul, mGnssHcovMul, + " * Horiz. Covariance mult.: "); + sl_tools::getParam( + shared_from_this(), "gnss_fusion.v_covariance_mul", + mGnssVcovMul, mGnssVcovMul, + " * Vert. Covariance mult.: "); + + sl_tools::getParam( + shared_from_this(), "gnss_fusion.publish_utm_tf", + mPublishUtmTf, mPublishUtmTf, " * Publish UTM TF: "); + + sl_tools::getParam( + shared_from_this(), + "gnss_fusion.broadcast_utm_transform_as_parent_frame", + mUtmAsParent, mUtmAsParent, + " * Publish UTM TF as parent of 'map': "); + } +} + +void ZedCamera::getStreamingServerParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== STREAMING SERVER parameters ==="); + + bool stream_server = false; + sl_tools::getParam( + shared_from_this(), "stream_server.stream_enabled", + stream_server, stream_server, + " * Streaming Server enabled: "); + mStreamingServerRequired = stream_server; + + std::string codec = "H264"; + sl_tools::getParam(shared_from_this(), "stream_server.codec", codec, codec); + if (codec == "H264") { + mStreamingServerCodec = sl::STREAMING_CODEC::H264; + RCLCPP_INFO(get_logger(), " * Stream codec: H264"); + } else if (codec == "H265") { + mStreamingServerCodec = sl::STREAMING_CODEC::H265; + RCLCPP_INFO(get_logger(), " * Stream codec: H265"); + } else { + mStreamingServerCodec = sl::STREAMING_CODEC::H264; + RCLCPP_WARN_STREAM( + get_logger(), + "Invalid value for the parameter 'stream_server.codec': " << codec << + ". Using the default value."); + RCLCPP_INFO(get_logger(), " * Stream codec: H264"); + } + + sl_tools::getParam( + shared_from_this(), "stream_server.port", + mStreamingServerPort, mStreamingServerPort, + " * Stream port: ", false, 0, 65535); + + sl_tools::getParam( + shared_from_this(), "stream_server.bitrate", + mStreamingServerBitrate, mStreamingServerBitrate, " * Stream bitrate: ", false, 1000, 60000); + + sl_tools::getParam( + shared_from_this(), "stream_server.gop_size", + mStreamingServerGopSize, mStreamingServerGopSize, " * Stream GOP size: ", false, -1, 256); + + sl_tools::getParam( + shared_from_this(), "stream_server.chunk_size", + mStreamingServerChunckSize, mStreamingServerChunckSize, " * Stream Chunk size: ", false, 1024, + 65000); + + sl_tools::getParam( + shared_from_this(), "stream_server.adaptative_bitrate", + mStreamingServerAdaptiveBitrate, + mStreamingServerAdaptiveBitrate, " * Adaptive bitrate: "); + + sl_tools::getParam( + shared_from_this(), "stream_server.target_framerate", + mStreamingServerTargetFramerate, + mStreamingServerTargetFramerate, " * Target frame rate:", false, 0, 120); +} + +void ZedCamera::getAdvancedParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== ADVANCED parameters ==="); + + sl_tools::getParam( + shared_from_this(), "advanced.change_thread_priority", + mChangeThreadSched, mChangeThreadSched, + " * Change thread priority: "); + + if (mChangeThreadSched) { + mThreadSchedPolicy = "SCHED_OTHER"; + sl_tools::getParam( + shared_from_this(), "advanced.thread_sched_policy", + mThreadSchedPolicy, mThreadSchedPolicy, + " * Thread sched. policy: "); + + if (mThreadSchedPolicy == "SCHED_FIFO" || mThreadSchedPolicy == "SCHED_RR") { + if (!sl_tools::checkRoot()) { + RCLCPP_WARN_STREAM( + get_logger(), + "'sudo' permissions required to set " + << mThreadSchedPolicy + << " thread scheduling policy. Using Linux " + "default [SCHED_OTHER]"); + mThreadSchedPolicy = "SCHED_OTHER"; + } else { + sl_tools::getParam( + shared_from_this(), "advanced.thread_grab_priority", + mThreadPrioGrab, mThreadPrioGrab, + " * Grab thread priority: "); + sl_tools::getParam( + shared_from_this(), "advanced.thread_sensor_priority", + mThreadPrioSens, mThreadPrioSens, + " * Sensors thread priority: "); + sl_tools::getParam( + shared_from_this(), + "advanced.thread_pointcloud_priority", + mThreadPrioPointCloud, mThreadPrioPointCloud, + " * Point Cloud thread priority: "); + } + } + } +} + +rcl_interfaces::msg::SetParametersResult ZedCamera::callback_dynamicParamChange( + std::vector parameters) +{ + DEBUG_STREAM_COMM("Parameter change callback"); + + rcl_interfaces::msg::SetParametersResult result; + result.successful = true; + + DEBUG_STREAM_COMM("Modifying " << parameters.size() << " parameters"); + + int count = 0; + + for (const rclcpp::Parameter & param : parameters) { + count++; + + DEBUG_STREAM_COMM("Param #" << count << ": " << param.get_name()); + + + if (param.get_name() == "pos_tracking.transform_time_offset") { + rclcpp::ParameterType correctType = + rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + break; + } + + double val = param.as_double(); + mTfOffset = val; + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" << param.get_name() + << "' correctly set to " << val); + } else if (param.get_name() == "pos_tracking.path_pub_rate") { + rclcpp::ParameterType correctType = + rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + break; + } + + double val = param.as_double(); + + if (val < -1.0 || val > mCamGrabFrameRate) { + result.successful = false; + result.reason = + param.get_name() + + " must be >= -1 and <= `general.grab_frame_rate` (0 or -1 = no limit)"; + RCLCPP_WARN_STREAM(get_logger(), result.reason); + break; + } + if (val <= 0.0) { + val = static_cast(mCamGrabFrameRate); + } + + mPathPubRate = val; + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" << param.get_name() + << "' correctly set to " << val); + } else if (param.get_name() == "mapping.fused_pointcloud_freq") { + rclcpp::ParameterType correctType = + rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + break; + } + + double val = param.as_double(); + + if (val < -1.0 || val > mPcPubRate) { + result.successful = false; + result.reason = param.get_name() + + " must be >= -1 and <= `point_cloud_freq` (0 or -1 = no limit)"; + RCLCPP_WARN_STREAM(get_logger(), result.reason); + break; + } + if (val <= 0.0) { + val = mPcPubRate; + } + + mFusedPcPubRate = val; + startFusedPcTimer(mFusedPcPubRate); // Reset publishing timer + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" << param.get_name() + << "' correctly set to " << val); + } else if (param.get_name() == "sensors.sensors_pub_rate") { + rclcpp::ParameterType correctType = + rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + break; + } + double value = param.as_double(); + if (value != mSensPubRate) { + mSensPubRate = value; + mPubImuTF_sec->setNewSize(static_cast(mSensPubRate)); + mImuPeriodMean_sec->setNewSize(static_cast(mSensPubRate)); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" << param.get_name() + << "' correctly set to " + << value); + } + } else if (param.get_name() == "svo.replay_rate") { + rclcpp::ParameterType correctType = + rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + break; + } + double value = param.as_double(); + + mSvoRate = value; + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" << param.get_name() + << "' correctly set to " << value); + } + + // ----> Video/Depth dynamic parameters + if (!handleVideoDepthDynamicParams(param, result)) { + break; + } + // <---- Video/Depth dynamic parameters + + // ----> Object Detection dynamic parameters + if (mUsingCustomOd) { + if (!handleCustomOdDynamicParams(param, result)) { + break; + } + } else { + if (!handleOdDynamicParams(param, result)) { + break; + } + } + // <---- Object Detection dynamic parameters + + // ----> Body Tracking dynamica parameters + if (!handleBodyTrkDynamicParams(param, result)) { + break; + } + // <---- Body Tracking dynamica parameters + } + + if (result.successful) { + DEBUG_STREAM_COMM( + "Correctly set " << count << "/" << parameters.size() + << " parameters"); + } else { + DEBUG_STREAM_COMM( + "Correctly set " << count - 1 << "/" + << parameters.size() << " parameters"); + } + + return result; +} + +void ZedCamera::setTFCoordFrameNames() +{ + // ----> Coordinate frames + mCenterFrameId = mCameraName + "_camera_center"; + mLeftCamFrameId = mCameraName + "_left_camera_frame"; + mLeftCamOptFrameId = mCameraName + "_left_camera_frame_optical"; + mRightCamFrameId = mCameraName + "_right_camera_frame"; + mRightCamOptFrameId = mCameraName + "_right_camera_frame_optical"; + + mImuFrameId = mCameraName + "_imu_link"; + mBaroFrameId = mCenterFrameId; // mCameraName + "_baro_link"; + mMagFrameId = mImuFrameId; // mCameraName + "_mag_link"; + mTempLeftFrameId = mLeftCamFrameId; // mCameraName + "_temp_left_link"; + mTempRightFrameId = mRightCamFrameId; // mCameraName + "_temp_right_link"; + + mDepthFrameId = mLeftCamFrameId; + mDepthOptFrameId = mLeftCamOptFrameId; + mPointCloudFrameId = mDepthFrameId; + + // Print TF frames + RCLCPP_INFO_STREAM(get_logger(), "=== TF FRAMES ==="); + RCLCPP_INFO_STREAM(get_logger(), " * Map\t\t\t-> " << mMapFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Odometry\t\t-> " << mOdomFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Base\t\t\t-> " << mBaseFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Camera\t\t-> " << mCenterFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Left\t\t\t-> " << mLeftCamFrameId); + RCLCPP_INFO_STREAM( + get_logger(), + " * Left Optical\t\t-> " << mLeftCamOptFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Right\t\t\t-> " << mRightCamFrameId); + RCLCPP_INFO_STREAM( + get_logger(), + " * Right Optical\t\t-> " << mRightCamOptFrameId); + if (!mDepthDisabled) { + RCLCPP_INFO_STREAM(get_logger(), " * Depth\t\t\t-> " << mDepthFrameId); + RCLCPP_INFO_STREAM( + get_logger(), + " * Depth Optical\t\t-> " << mDepthOptFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Point Cloud\t\t-> " << mPointCloudFrameId); + } + + if (!sl_tools::isZED(mCamRealModel)) { + RCLCPP_INFO_STREAM(get_logger(), " * IMU\t\t\t-> " << mImuFrameId); + + if (sl_tools::isZED2OrZED2i(mCamUserModel)) { + RCLCPP_INFO_STREAM(get_logger(), " * Barometer\t\t-> " << mBaroFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Magnetometer\t\t-> " << mMagFrameId); + RCLCPP_INFO_STREAM( + get_logger(), + " * Left Temperature\t-> " << mTempLeftFrameId); + RCLCPP_INFO_STREAM( + get_logger(), + " * Right Temperature\t-> " << mTempRightFrameId); + } + } + // <---- Coordinate frames +} + +void ZedCamera::initPublishers() +{ + RCLCPP_INFO(get_logger(), "=== PUBLISHED TOPICS ==="); + + // ----> Topics names definition + mPointcloudFusedTopic = mTopicRoot + "mapping/fused_cloud"; + + std::string object_det_topic_root = "obj_det"; + mObjectDetTopic = mTopicRoot + object_det_topic_root + "/objects"; + + std::string body_trk_topic_root = "body_trk"; + mBodyTrkTopic = mTopicRoot + body_trk_topic_root + "/skeletons"; + + // Set the positional tracking topic names + mPoseTopic = mTopicRoot + "pose"; + mPoseStatusTopic = mPoseTopic + "/status"; + mPoseCovTopic = mPoseTopic + "_with_covariance"; + mGnssPoseTopic = mPoseTopic + "/filtered"; + mGnssPoseStatusTopic = mGnssPoseTopic + "/status"; + mGeoPoseTopic = mTopicRoot + "geo_pose"; + mGeoPoseStatusTopic = mGeoPoseTopic + "/status"; + mFusedFixTopic = mPoseTopic + "/fused_fix"; + mOriginFixTopic = mPoseTopic + "/origin_fix"; + + mPointcloud3DLandmarksTopic = mPoseTopic + "/landmarks"; + + mOdomTopic = mTopicRoot + "odom"; + mOdomPathTopic = mTopicRoot + "path_odom"; + mPosePathTopic = mTopicRoot + "path_map"; + + // Set the Sensors topic names + std::string temp_topic_root = "temperature"; + std::string imuTopicRoot = "imu"; + std::string imu_topic_name = "data"; + std::string imu_topic_raw_name = "data_raw"; + std::string imu_topic_mag_name = "mag"; + // std::string imu_topic_mag_raw_name = "mag_raw"; + std::string pressure_topic_name = "atm_press"; + + std::string imu_topic = mTopicRoot + imuTopicRoot + "/" + imu_topic_name; + std::string imu_topic_raw = + mTopicRoot + imuTopicRoot + "/" + imu_topic_raw_name; + std::string imu_temp_topic = + mTopicRoot + temp_topic_root + "/" + imuTopicRoot; + std::string imu_mag_topic = + mTopicRoot + imuTopicRoot + "/" + imu_topic_mag_name; + // std::string imu_mag_topic_raw = imuTopicRoot + "/" + + // imu_topic_mag_raw_name; + std::string pressure_topic = + mTopicRoot + /*imuTopicRoot + "/" +*/ pressure_topic_name; + std::string temp_topic_left = mTopicRoot + temp_topic_root + "/left"; + std::string temp_topic_right = mTopicRoot + temp_topic_root + "/right"; + + // Status topic name + std::string status_root = mTopicRoot + "status/"; + std::string svo_status_topic = status_root + "svo"; + std::string health_status_topic = status_root + "health"; + std::string heartbeat_topic = status_root + "heartbeat"; + // <---- Topics names definition + + // ----> SVO Status publisher + if (mSvoMode) { + if (mPublishStatus) { + mPubSvoStatus = create_publisher( + svo_status_topic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubSvoStatus->get_topic_name()); + } + if (mUseSvoTimestamp && mPublishSvoClock) { + auto clock_qos = rclcpp::ClockQoS(); + clock_qos.reliability(rclcpp::ReliabilityPolicy::Reliable); // REQUIRED + mPubClock = + create_publisher("/clock", clock_qos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubClock->get_topic_name()); + } + } + // <---- SVO Status publisher + + if (mPublishStatus) { + // ----> Health Status publisher + mPubHealthStatus = create_publisher( + health_status_topic, + mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubHealthStatus->get_topic_name()); + // <---- Health Status publisher + + // ----> Heartbeat Status publisher + mPubHeartbeatStatus = create_publisher( + heartbeat_topic, + mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubHeartbeatStatus->get_topic_name()); + // <---- Heartbeat Status publisher + } + + initVideoDepthPublishers(); + + // POS. TRACKING and GNSS FUSION parameters +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is + // disabled + if (!mDepthDisabled || mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (!mDepthDisabled) { +#endif + // ----> Pos Tracking + if (mPublishOdomPose) { + mPubPose = create_publisher( + mPoseTopic, + mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubPose->get_topic_name()); + if (mPublishPoseCov) { + mPubPoseCov = + create_publisher( + mPoseCovTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " << mPubPoseCov->get_topic_name()); + } + if (mPublishStatus) { + mPubPoseStatus = create_publisher( + mPoseStatusTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mPubPoseStatus->get_topic_name()); + } + mPubOdom = + create_publisher(mOdomTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubOdom->get_topic_name()); + + if (mPublishPath) { + mPubPosePath = + create_publisher(mPosePathTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mPubPosePath->get_topic_name()); + mPubOdomPath = + create_publisher(mOdomPathTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mPubOdomPath->get_topic_name()); + } + if (mPublish3DLandmarks) { +#ifdef FOUND_POINT_CLOUD_TRANSPORT + mPub3DLandmarks = point_cloud_transport::create_publisher( + shared_from_this(), mPointcloud3DLandmarksTopic, mQos.get_rmw_qos_profile(), + mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic " + << mPub3DLandmarks.getTopic()); +#else + mPub3DLandmarks = create_publisher( + mPointcloud3DLandmarksTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic " + << mPub3DLandmarks->get_topic_name()); +#endif + } + } + if (mGnssFusionEnabled) { + mPubGnssPose = create_publisher( + mGnssPoseTopic, + mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic (GNSS): " + << mPubGnssPose->get_topic_name()); + mPubGnssPoseStatus = create_publisher( + mGnssPoseStatusTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubGnssPoseStatus->get_topic_name()); + mPubGeoPose = create_publisher( + mGeoPoseTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic (GNSS): " + << mPubGeoPose->get_topic_name()); + mPubGeoPoseStatus = create_publisher( + mGeoPoseStatusTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + "Advertised on topic (GNSS): " + << mPubGeoPoseStatus->get_topic_name()); + mPubFusedFix = create_publisher( + mFusedFixTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic (GNSS): " + << mPubFusedFix->get_topic_name()); + + mPubOriginFix = create_publisher( + mOriginFixTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic (GNSS origin): " + << mPubOriginFix->get_topic_name()); + + } + // <---- Pos Tracking + + // ----> Mapping + if (mMappingEnabled) { +#ifdef FOUND_POINT_CLOUD_TRANSPORT + mPubFusedCloud = point_cloud_transport::create_publisher( + shared_from_this(), mPointcloudFusedTopic, mQos.get_rmw_qos_profile(), + mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic " + << mPubFusedCloud.getTopic() + << " @ " << mFusedPcPubRate + << " Hz"); +#else + mPubFusedCloud = create_publisher( + mPointcloudFusedTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic " + << mPubFusedCloud->get_topic_name() + << " @ " << mFusedPcPubRate + << " Hz"); +#endif + } + + if (mPublishDetPlane) { + std::string marker_topic = mTopicRoot + "plane_marker"; + std::string plane_topic = mTopicRoot + "plane"; + // Rviz markers publisher + mPubMarker = create_publisher( + marker_topic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubMarker->get_topic_name()); + // Detected planes publisher + mPubPlane = create_publisher( + plane_topic, mQos, + mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubPlane->get_topic_name()); + } + // <---- Mapping + } + + // ----> Sensors + if (!sl_tools::isZED(mCamRealModel)) { + if (mPublishSensImu) { + mPubImu = create_publisher(imu_topic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubImu->get_topic_name()); + } + if (mPublishSensImuRaw) { + mPubImuRaw = + create_publisher(imu_topic_raw, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubImuRaw->get_topic_name()); + } + + if (sl_tools::isZED2OrZED2i(mCamRealModel) || + sl_tools::isZEDX(mCamRealModel)) + { + if (mPublishSensTemp) { + mPubImuTemp = create_publisher( + imu_temp_topic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mPubImuTemp->get_topic_name()); + } + } + + if (sl_tools::isZED2OrZED2i(mCamRealModel)) { + if (mPublishSensMag) { + mPubImuMag = create_publisher( + imu_mag_topic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mPubImuMag->get_topic_name()); + } + if (mPublishSensBaro) { + mPubPressure = create_publisher( + pressure_topic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mPubPressure->get_topic_name()); + } + if (mPublishSensTemp) { + mPubTempL = create_publisher( + temp_topic_left, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " << mPubTempL->get_topic_name()); + mPubTempR = create_publisher( + temp_topic_right, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " << mPubTempR->get_topic_name()); + } + } + + // ----> Camera/imu transform message + if (mPublishSensImuTransf) { + std::string cam_imu_tr_topic = mTopicRoot + "left_cam_imu_transform"; + auto qos = mQos; + if (!mUsingIPC) { + // Use TRANSIENT_LOCAL durability if not using intra-process comms + qos = qos.durability(rclcpp::DurabilityPolicy::TransientLocal); + } + mPubCamImuTransf = create_publisher( + cam_imu_tr_topic, qos, mPubOpt); + + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " << mPubCamImuTransf->get_topic_name()); + } + + sl::Orientation sl_rot = mSlCamImuTransf.getOrientation(); + sl::Translation sl_tr = mSlCamImuTransf.getTranslation(); + RCLCPP_INFO( + get_logger(), "Camera-IMU Translation: \n %g %g %g", sl_tr.x, + sl_tr.y, sl_tr.z); + RCLCPP_INFO( + get_logger(), "Camera-IMU Rotation:\n%s", + sl_rot.getRotationMatrix().getInfos().c_str()); + // <---- Camera/imu transform message + } + // <---- Sensors +} + +void ZedCamera::initSubscribers() +{ + RCLCPP_INFO(get_logger(), "=== Subscribers ==="); + // ----> Clicked Point Subscriber + /* From `$ ros2 topic info /clicked_point -v` + QoS profile: + Reliability: RMW_QOS_POLICY_RELIABILITY_RELIABLE + Durability: RMW_QOS_POLICY_DURABILITY_VOLATILE + Lifespan: 2147483651294967295 nanoseconds + Deadline: 2147483651294967295 nanoseconds + Liveliness: RMW_QOS_POLICY_LIVELINESS_AUTOMATIC + Liveliness lease duration: 2147483651294967295 nanoseconds + */ + int sub_count = 0; + + if (!mDepthDisabled && mPosTrackingEnabled) { + mClickedPtSub = create_subscription( + mClickedPtTopic, mQos, + std::bind(&ZedCamera::callback_clickedPoint, this, _1), mSubOpt); + sub_count++; + + RCLCPP_INFO_STREAM( + get_logger(), " * Plane detection: '" + << mClickedPtSub->get_topic_name() + << "'"); + } + // <---- Clicked Point Subscriber + + // ----> GNSS Fix Subscriber + /* From `$ ros2 topic info /fix -v` + QoS profile: + Reliability: RELIABLE + History (Depth): KEEP_LAST (10) + Durability: VOLATILE + Lifespan: Infinite + Deadline: Infinite + Liveliness: AUTOMATIC + Liveliness lease duration: Infinite + */ + if (mGnssFusionEnabled && !mSvoMode) { + mGnssMsgReceived = false; + mGnssFixValid = false; + + mGnssFixSub = create_subscription( + mGnssTopic, mQos, std::bind(&ZedCamera::callback_gnssFix, this, _1), + mSubOpt); + sub_count++; + + RCLCPP_INFO_STREAM( + get_logger(), " * GNSS Fix: '" << mGnssFixSub->get_topic_name() << "'"); + } + // <---- GNSS Fix Subscriber + + // ----> Clock Subscriber + /* From `$ ros2 topic info /clock -v` + + QoS profile: + Reliability: RELIABLE + History (Depth): KEEP_LAST (10) + Durability: VOLATILE + Lifespan: Infinite + Deadline: Infinite + Liveliness: AUTOMATIC + Liveliness lease duration: Infinite + */ + + if (mUseSimTime) { + mClockAvailable = false; + + mClockSub = create_subscription( + "/clock", mQos, std::bind(&ZedCamera::callback_clock, this, _1), + mSubOpt); + sub_count++; + + RCLCPP_INFO_STREAM( + get_logger(), + " * Sim Clock: '" << mClockSub->get_topic_name() << "'"); + } + + if (sub_count == 0) { + RCLCPP_INFO_STREAM(get_logger(), " * No subscribers"); + } +} + +bool ZedCamera::startCamera() +{ + RCLCPP_INFO(get_logger(), "=== STARTING CAMERA ==="); + + // // CUDA context check + // CUcontext * primary_cuda_context; + // cuCtxGetCurrent(primary_cuda_context); + // int ctx_gpu_id; + // cudaGetDevice(&ctx_gpu_id); + + // Create a ZED object + mZed = std::make_shared(); + + // ----> SDK version + RCLCPP_INFO( + get_logger(), "ZED SDK Version: %d.%d.%d - Build %s", + ZED_SDK_MAJOR_VERSION, ZED_SDK_MINOR_VERSION, + ZED_SDK_PATCH_VERSION, ZED_SDK_BUILD_ID); + // <---- SDK version + + // ----> TF2 Transform + mTfBuffer = std::make_unique(get_clock()); + mTfListener = std::make_unique( + *mTfBuffer); // Start TF Listener thread + mTfBroadcaster = std::make_unique(this); + + mStaticTfPublished = false; + mStaticImuTfPublished = false; + if (!mUsingIPC) { + mStaticTfBroadcaster = + std::make_unique(this); + } else { // Cannot use TRANSIENT_LOCAL with intra-process comms + mStaticTfBroadcaster.reset(); + } + // <---- TF2 Transform + + // ----> ZED configuration + + // if (primary_cuda_context) { + // mInitParams.sdk_cuda_ctx = *primary_cuda_context; + // } else { + // RCLCPP_INFO( + // get_logger(), + // "No ready CUDA context found, using default ZED SDK context."); + // } + + if (mSimMode) { // Simulation? + RCLCPP_INFO_STREAM( + get_logger(), "=== CONNECTING TO THE SIMULATION SERVER [" + << mSimAddr.c_str() << ":" << mSimPort + << "] ==="); + + mInitParams.input.setFromStream(mSimAddr.c_str(), mSimPort); + } else if (!mSvoFilepath.empty()) { + RCLCPP_INFO(get_logger(), "=== SVO OPENING ==="); + + mInitParams.input.setFromSVOFile(mSvoFilepath.c_str()); + mInitParams.svo_real_time_mode = mSvoRealtime; +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + mInitParams.svo_decryption_key = mSvoDecryptionKey.c_str(); +#endif + } else if (!mStreamAddr.empty()) { + RCLCPP_INFO(get_logger(), "=== LOCAL STREAMING OPENING ==="); + + mInitParams.input.setFromStream( + mStreamAddr.c_str(), + static_cast(mStreamPort)); + } else { + RCLCPP_INFO(get_logger(), "=== CAMERA OPENING ==="); + + mInitParams.camera_fps = mCamGrabFrameRate; + mInitParams.grab_compute_capping_fps = static_cast(mGrabComputeCappingFps); + mInitParams.camera_resolution = static_cast(mCamResol); + mInitParams.async_image_retrieval = mAsyncImageRetrieval; + mInitParams.enable_image_validity_check = mImageValidityCheck; + + if (mCamUserModel == sl::MODEL::VIRTUAL_ZED_X) { + if (mCamVirtualSerialNumbers.size() == 2) { + // Generate the virtual serial number from the two real serial numbers + auto virtual_sn = + sl::generateVirtualStereoSerialNumber( + mCamVirtualSerialNumbers[0], + mCamVirtualSerialNumbers[1]); + mInitParams.input.setVirtualStereoFromSerialNumbers( + mCamVirtualSerialNumbers[0], mCamVirtualSerialNumbers[1], virtual_sn); + } else if (mCamVirtualCameraIds.size() == 2) { + + // Here we need the ZED X One serial numbers to generate the virtual camera SN + auto cams = sl::CameraOne::getDeviceList(); + std::vector serials; + for (const auto & cam : cams) { + if (std::any_of( + mCamVirtualCameraIds.begin(), mCamVirtualCameraIds.end(), + [&cam](int id) {return cam.id == id;})) + { + serials.push_back(cam.serial_number); + } + } + + if (serials.size() < 2) { + RCLCPP_ERROR( + get_logger(), + "To use VIRTUAL_ZED_X model with camera IDs, the cameras must be connected and recognized by the system."); + return false; + } + + // Generate the virtual serial number from the two real serial numbers + auto virtual_sn = sl::generateVirtualStereoSerialNumber(serials[0], serials[1]); + + mInitParams.input.setVirtualStereoFromCameraIDs( + mCamVirtualCameraIds[0], mCamVirtualCameraIds[1], virtual_sn); + } else { + RCLCPP_ERROR( + get_logger(), + "To use VIRTUAL_ZED_X model, you must provide either two VALID serial numbers or two VALID camera IDs."); + return false; + } + } else { + if (mCamSerialNumber > 0) { + mInitParams.input.setFromSerialNumber(mCamSerialNumber); + } else if (mCamId >= 0) { + mInitParams.input.setFromCameraID(mCamId); + } + } + } + + mInitParams.coordinate_system = ROS_COORDINATE_SYSTEM; + mInitParams.coordinate_units = ROS_MEAS_UNITS; + mInitParams.depth_mode = mDepthMode; + + // Set env var for custom depth model override if specified + if (!mDepthModelOverride.empty()) { +#if (ZED_SDK_MAJOR_VERSION < 5) || \ + (ZED_SDK_MAJOR_VERSION == 5 && ZED_SDK_MINOR_VERSION < 2) || \ + (ZED_SDK_MAJOR_VERSION == 5 && ZED_SDK_MINOR_VERSION == 2 && ZED_SDK_PATCH_VERSION < 2) + RCLCPP_WARN( + get_logger(), + "*** Depth model override requires ZED SDK >= 5.2.2. " + "Current SDK version is %d.%d.%d. The override will likely be ignored. ***", + ZED_SDK_MAJOR_VERSION, ZED_SDK_MINOR_VERSION, ZED_SDK_PATCH_VERSION); +#endif + std::string depth_mode_name = sl_tools::toUpper( + std::string(sl::toString(mDepthMode).c_str())); + std::string env_var = "ZED_SDK_OVERRIDE_" + depth_mode_name; + setenv(env_var.c_str(), mDepthModelOverride.c_str(), 1); + RCLCPP_WARN_STREAM( + get_logger(), + "*** DEPTH MODEL OVERRIDE ACTIVE ***\n" + << " Mode: " << sl::toString(mDepthMode).c_str() << "\n" + << " Model: " << mDepthModelOverride << "\n" + << " Env var: " << env_var << "=" << mDepthModelOverride); + } + + mInitParams.sdk_verbose = mVerbose; + mInitParams.sdk_verbose_log_file = mVerboseLogFile.c_str(); + mInitParams.sdk_gpu_id = mGpuId; + if (mDepthStabilization >= 0) { + mInitParams.depth_stabilization = mDepthStabilization; + } // else: keep SDK constructed default + mInitParams.camera_image_flip = (mCameraFlip ? sl::FLIP_MODE::ON : sl::FLIP_MODE::OFF); + mInitParams.depth_minimum_distance = mCamMinDepth; + mInitParams.depth_maximum_distance = mCamMaxDepth; + + if (!mOpencvCalibFile.empty()) { + mInitParams.optional_opencv_calibration_file = mOpencvCalibFile.c_str(); + } + + mInitParams.camera_disable_self_calib = !mCameraSelfCalib; + mInitParams.enable_image_enhancement = true; + mInitParams.enable_right_side_measure = false; + + mInitParams.async_grab_camera_recovery = + true; // Camera recovery is handled asynchronously to provide information + // about this status + + // Set the maximum working resolution between video and point cloud to boost the pipeline processing + if (mMatResol.width > mPcResol.width) { + mInitParams.maximum_working_resolution = mMatResol; + } else { + mInitParams.maximum_working_resolution = mPcResol; + } + // <---- ZED configuration + + // ----> Try to connect to a camera, to a stream, or to load an SVO + sl_tools::StopWatch connectTimer(get_clock()); + + mThreadStop = false; + mGrabStatus = sl::ERROR_CODE::LAST; + + while (1) { + rclcpp::sleep_for(500ms); + + mConnStatus = mZed->open(mInitParams); + + if (mConnStatus == sl::ERROR_CODE::SUCCESS) { + DEBUG_STREAM_COMM("Opening successfull"); + mUptimer.tic(); // Sets the beginning of the camera connection time + break; + } + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + if (mConnStatus == sl::ERROR_CODE::DRIVER_FAILURE) { + RCLCPP_ERROR_STREAM( + get_logger(), + "ZED X Driver failure: " + << sl::toVerbose(mConnStatus) + << ". Please verify that the ZED drivers are correctly installed."); + return false; + } +#endif + + if (mConnStatus == sl::ERROR_CODE::INVALID_CALIBRATION_FILE) { + if (mOpencvCalibFile.empty()) { + RCLCPP_ERROR_STREAM(get_logger(), "Calibration file error: " << sl::toVerbose(mConnStatus)); + } else { + RCLCPP_ERROR_STREAM( + get_logger(), + "If you are using a custom OpenCV calibration file, please check " + "the correctness of the path of the calibration file " + "in the parameter 'general.optional_opencv_calibration_file': '" + << mOpencvCalibFile << "'."); + RCLCPP_ERROR( + get_logger(), + "If the file exists, it may contain invalid information."); + } + return false; + } + + if (mSvoMode) { + RCLCPP_WARN( + get_logger(), "Error opening SVO: %s", + sl::toString(mConnStatus).c_str()); + return false; + } else if (mSimMode) { + RCLCPP_WARN( + get_logger(), "Error connecting to the simulation server: %s", + sl::toString(mConnStatus).c_str()); + } else { + RCLCPP_WARN( + get_logger(), "Error opening camera: %s", + sl::toString(mConnStatus).c_str()); + if (mConnStatus == sl::ERROR_CODE::CAMERA_DETECTION_ISSUE && + sl_tools::isZEDM(mCamUserModel)) + { + RCLCPP_INFO( + get_logger(), + "Try to flip the USB3 Type-C connector and verify the USB3 " + "connection"); + } else { + RCLCPP_INFO(get_logger(), "Please verify the camera connection"); + } + } + + if (!rclcpp::ok() || mThreadStop) { + RCLCPP_INFO(get_logger(), "ZED activation interrupted by user."); + return false; + } + + if (connectTimer.toc() > mMaxReconnectTemp * mCamTimeoutSec) { + RCLCPP_ERROR(get_logger(), "Camera detection timeout"); + return false; + } + + mDiagUpdater.force_update(); + + rclcpp::sleep_for(std::chrono::seconds(mCamTimeoutSec)); + } + // ----> Try to connect to a camera, to a stream, or to load an SVO + + // ----> Set SVO first frame if required + if (mSvoMode && mSvoFrameStart != 0) { + int svo_frames = mZed->getSVONumberOfFrames(); + + if (mSvoFrameStart > svo_frames) { + RCLCPP_ERROR_STREAM( + get_logger(), + "The SVO contains " << svo_frames << " frames. The requested starting frame (" + << mSvoFrameStart << ") is invalid."); + return false; + } + + mZed->setSVOPosition(mSvoFrameStart); + RCLCPP_WARN_STREAM( + get_logger(), + "SVO playing from frame #" << mSvoFrameStart); + } + + + // ----> If SVO and GNSS enabled check that it's a valid SV0 Gen.2 + if (mSvoMode && mGnssFusionEnabled) { + // TODO(Walter) Check SVO version when it's available + + mGnssReplay = std::make_unique(mZed); + if (!mGnssReplay->initialize()) { + RCLCPP_ERROR(get_logger(), "The SVO file does not contain valid GNSS information."); + return false; + } else { + RCLCPP_INFO( + get_logger(), + "GNSS information will be retrieved from the SVO file."); + } + } + // <---- If SVO and GNSS enabled check that it's a valid SV0 Gen.2 + + // ----> If SVO and positional tracking Gen3 check that it's a valid SVO Gen3 + if (mSvoMode && mPosTrackingEnabled && + mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) + { + // TODO(Walter) Check SVO version when it's available + } + // <---- If SVO and positional tracking Gen3 check that it's a valid SVO Gen3 + + // ----> Camera information + sl::CameraInformation camInfo = mZed->getCameraInformation(); + + float realFps = camInfo.camera_configuration.fps; + if (realFps != static_cast(mCamGrabFrameRate)) { + if (!mSvoMode) { + RCLCPP_WARN_STREAM( + get_logger(), + "!!! `general.grab_frame_rate` value is not valid: '" + << mCamGrabFrameRate + << "'. Automatically replaced with '" << realFps + << "'. Please fix the parameter !!!"); + } + mCamGrabFrameRate = realFps; + + // ----> Check publishing rates + if (mVdPubRate > mCamGrabFrameRate) { + mVdPubRate = mCamGrabFrameRate; + RCLCPP_WARN_STREAM( + get_logger(), + "Video/Depth publishing rate was too high [" << mVdPubRate << "], capped to real grab rate: " << + mCamGrabFrameRate); + } + if (mPcPubRate > mCamGrabFrameRate) { + mPcPubRate = mCamGrabFrameRate; + RCLCPP_WARN_STREAM( + get_logger(), + "PointCloud publishing rate was too high [" + << mPcPubRate << "], capped to real grab rate: " + << mCamGrabFrameRate); + } + // <---- Check publishing rates + } + if (mSvoMode && !mSvoRealtime) { + mVdPubRate = static_cast(mCamGrabFrameRate) * mSvoRate; + } + + // CUdevice devid; + cuCtxGetDevice(&mGpuId); + RCLCPP_INFO_STREAM(get_logger(), " * ZED SDK running on GPU #" << mGpuId); + + // Camera model + mCamRealModel = camInfo.camera_model; + + if (mCamRealModel == sl::MODEL::ZED) { + if (mCamUserModel != sl::MODEL::ZED) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zed'"); + } + } else if (mCamRealModel == sl::MODEL::ZED_M) { + if (mCamUserModel != sl::MODEL::ZED_M) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zedm'"); + } + } else if (mCamRealModel == sl::MODEL::ZED2) { + if (mCamUserModel != sl::MODEL::ZED2) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zed2'"); + } + } else if (mCamRealModel == sl::MODEL::ZED2i) { + if (mCamUserModel != sl::MODEL::ZED2i) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zed2i'"); + } + } else if (mCamRealModel == sl::MODEL::ZED_X) { + if (mCamUserModel != sl::MODEL::ZED_X) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zedx'"); + } + } else if (mCamRealModel == sl::MODEL::ZED_XM) { + if (mCamUserModel != sl::MODEL::ZED_XM) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zedxm'"); + } + } else if (mCamRealModel == sl::MODEL::VIRTUAL_ZED_X) { + if (mCamUserModel != sl::MODEL::VIRTUAL_ZED_X) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'virtual'"); + } + } else if (mCamRealModel == sl::MODEL::ZED_X_HDR) { + if (mCamUserModel != sl::MODEL::ZED_X_HDR) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zedxhdr'"); + } + } else if (mCamRealModel == sl::MODEL::ZED_X_HDR_MINI) { + if (mCamUserModel != sl::MODEL::ZED_X_HDR_MINI) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zedxhdrmini'"); + } + } else if (mCamRealModel == sl::MODEL::ZED_X_HDR_MAX) { + if (mCamUserModel != sl::MODEL::ZED_X_HDR_MAX) { + RCLCPP_WARN( + get_logger(), + "Camera model does not match user parameter. Please modify " + "the value of the parameter 'general.camera_model' to 'zedxhdrmax'"); + } + } + + RCLCPP_INFO_STREAM( + get_logger(), " * Camera Model -> " + << sl::toString(mCamRealModel).c_str()); + mCamSerialNumber = camInfo.serial_number; + RCLCPP_INFO_STREAM(get_logger(), " * Serial Number -> " << mCamSerialNumber); + + // ----> Update HW ID + std::string hw_id = std::string("Stereolabs "); + hw_id += sl::toString(mCamRealModel).c_str(); + hw_id += " - '" + mCameraName + "'" + " - S/N: " + std::to_string(mCamSerialNumber); + mDiagUpdater.setHardwareID(hw_id); + mDiagUpdater.force_update(); + // <---- Update HW ID + + RCLCPP_INFO_STREAM( + get_logger(), + " * Focal Length\t-> " + << camInfo.camera_configuration.calibration_parameters + .left_cam.focal_length_metric + << " mm"); + + RCLCPP_INFO_STREAM( + get_logger(), + " * Input\t-> " + << sl::toString(mZed->getCameraInformation().input_type).c_str()); + if (mSvoMode) { + #if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 50 + RCLCPP_INFO( + get_logger(), " * SVO resolution -> %dx%d", + mZed->getCameraInformation().camera_configuration.resolution.width, + mZed->getCameraInformation().camera_configuration.resolution.height); + #else + RCLCPP_INFO( + get_logger(), " * SVO resolution -> %ldx%ld", + mZed->getCameraInformation().camera_configuration.resolution.width, + mZed->getCameraInformation().camera_configuration.resolution.height); + #endif + RCLCPP_INFO_STREAM( + get_logger(), + " * SVO framerate\t -> " + << (mZed->getCameraInformation().camera_configuration.fps)); + } + + // Firmwares + if (!mSvoMode) { + mCamFwVersion = camInfo.camera_configuration.firmware_version; + + RCLCPP_INFO_STREAM( + get_logger(), + " * Camera FW Version -> " << mCamFwVersion); + if (!sl_tools::isZED(mCamRealModel)) { + mSensFwVersion = camInfo.sensors_configuration.firmware_version; + RCLCPP_INFO_STREAM( + get_logger(), + " * Sensors FW Version -> " << mSensFwVersion); + } + } + + // Camera/IMU transform + if (!sl_tools::isZED(mCamRealModel)) { + mSlCamImuTransf = camInfo.sensors_configuration.camera_imu_transform; + + DEBUG_SENS("Camera-IMU Transform:\n%s", mSlCamImuTransf.getInfos().c_str()); + } + + mCamWidth = camInfo.camera_configuration.resolution.width; + mCamHeight = camInfo.camera_configuration.resolution.height; + + RCLCPP_INFO_STREAM( + get_logger(), " * Camera grab size -> " + << mCamWidth << "x" << mCamHeight); + + int pub_w = static_cast(std::round(mCamWidth / mCustomDownscaleFactor)); + int pub_h = static_cast(std::round(mCamHeight / mCustomDownscaleFactor)); + mMatResol = sl::Resolution(pub_w, pub_h); + + RCLCPP_INFO_STREAM( + get_logger(), " * Color/Depth publishing size -> " + << mMatResol.width << "x" << mMatResol.height); + // <---- Camera information + + // ----> Point Cloud resolution + int pc_w = 0, pc_h = 0; + switch (mPcResolution) { + case PcRes::PUB: // Same as image and depth map + pc_w = pub_w; + pc_h = pub_h; + break; + case PcRes::FULL: + pc_w = NEURAL_W; + pc_h = NEURAL_H; + break; + case PcRes::COMPACT: + pc_w = NEURAL_W / 2; + pc_h = NEURAL_H / 2; + break; + case PcRes::REDUCED: + pc_w = NEURAL_W / 4; + pc_h = NEURAL_H / 4; + break; + } + mPcResol = sl::Resolution(pc_w, pc_h); + + RCLCPP_INFO_STREAM( + get_logger(), " * Point Cloud publishing size -> " + << mPcResol.width << "x" << mPcResol.height); + // <---- Point Cloud resolution1 + + + // ----> Set Region of Interest + if (!mDepthDisabled) { + if (mAutoRoiEnabled) { + RCLCPP_INFO(get_logger(), "=== Enabling Automatic ROI ==="); + + sl::RegionOfInterestParameters roi_param; + roi_param.depth_far_threshold_meters = mRoiDepthFarThresh; + roi_param.image_height_ratio_cutoff = mRoiImgHeightRationCutOff; + roi_param.auto_apply_module = mRoiModules; + + sl::ERROR_CODE err = mZed->startRegionOfInterestAutoDetection(roi_param); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + " * Error while starting automatic ROI generation: " + << sl::toString(err).c_str()); + } else { + RCLCPP_INFO( + get_logger(), + " * Automatic Region of Interest generation started."); + } + } else if (!mRoyPolyParam.empty()) { + RCLCPP_INFO(get_logger(), "=== Setting Manual ROI ==="); + sl::Resolution resol(mCamWidth, mCamHeight); + std::vector sl_poly; + + DEBUG_ROI("Parse ROI Polygon parameter"); + std::string poly_str = parseRoiPoly(mRoyPolyParam, sl_poly); + DEBUG_STREAM_ROI("Parsed ROI Polygon: " << poly_str); + DEBUG_STREAM_ROI(" * Polygon size: " << sl_poly.size()); + + DEBUG_ROI("Create ROI Mask mat"); + sl::Mat roi_mask(resol, sl::MAT_TYPE::U8_C1, sl::MEM::CPU); + + // Create ROI mask + DEBUG_ROI("Generate ROI Mask"); + if (!sl_tools::generateROI(sl_poly, roi_mask)) { + RCLCPP_WARN( + get_logger(), + " * Error generating the manual region of interest image mask."); + } else { + DEBUG_ROI("Enable ROI"); + sl::ERROR_CODE err = mZed->setRegionOfInterest(roi_mask, mRoiModules); + DEBUG_ROI("ROI Enabled"); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + " * Error while setting ZED SDK manual region of interest: " + << sl::toString(err).c_str()); + } else { + RCLCPP_INFO( + get_logger(), + " * Manual Region of Interest correctly set."); + mManualRoiEnabled = true; + } + } + } + } + // <---- Set Region of Interest + + // ----> Check default camera settings + if (_debugCamCtrl && !mSvoMode) { + int value; + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting; + + if (!sl_tools::isZEDX(mCamRealModel)) { + setting = sl::VIDEO_SETTINGS::BRIGHTNESS; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::CONTRAST; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::HUE; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + } + + setting = sl::VIDEO_SETTINGS::SATURATION; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::SHARPNESS; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::GAMMA; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::AEC_AGC; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::EXPOSURE; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::GAIN; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::WHITEBALANCE_AUTO; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + setting = sl::VIDEO_SETTINGS::WHITEBALANCE_TEMPERATURE; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "Default value for " << sl::toString(setting).c_str() + << ": " << value); + + if (sl_tools::isZEDX(mCamRealModel)) { + int value_min, value_max; + + setting = sl::VIDEO_SETTINGS::EXPOSURE_TIME; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " + << sl::toString(setting).c_str() << ": " << value); + + setting = sl::VIDEO_SETTINGS::AUTO_EXPOSURE_TIME_RANGE; + err = mZed->getCameraSettings(setting, value_min, value_max); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() << ": " << + sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " << + sl::toString(setting).c_str() << ": [" << value_min << "," << + value_max + << "]"); + + if (!mStreamMode) { + setting = sl::VIDEO_SETTINGS::EXPOSURE_COMPENSATION; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " + << sl::toString(setting).c_str() << ": " << value); + } + + setting = sl::VIDEO_SETTINGS::ANALOG_GAIN; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " + << sl::toString(setting).c_str() << ": " << value); + + setting = sl::VIDEO_SETTINGS::AUTO_ANALOG_GAIN_RANGE; + err = mZed->getCameraSettings(setting, value_min, value_max); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() << ": " << + sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " << + sl::toString(setting).c_str() << ": [" << value_min << "," << + value_max + << "]"); + + setting = sl::VIDEO_SETTINGS::DIGITAL_GAIN; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " + << sl::toString(setting).c_str() << ": " << value); + + setting = sl::VIDEO_SETTINGS::AUTO_DIGITAL_GAIN_RANGE; + err = mZed->getCameraSettings(setting, value_min, value_max); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() << ": " << + sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " << + sl::toString(setting).c_str() << ": [" << value_min << "," << + value_max + << "]"); + + if (!mStreamMode) { + setting = sl::VIDEO_SETTINGS::DENOISING; + err = mZed->getCameraSettings(setting, value); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error Getting default param for " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_STREAM_CTRL( + "[ZEDX] Default value for " + << sl::toString(setting).c_str() << ": " << value); + } + } + } + // <----> Check default camera settings + + // ----> Camera Info messages + mLeftCamInfoMsg = std::make_shared(); + mLeftCamInfoRawMsg = std::make_shared(); + mRightCamInfoMsg = std::make_shared(); + mRightCamInfoRawMsg = std::make_shared(); + + setTFCoordFrameNames(); // Requires mZedRealCamModel available only after + // camera opening + + fillCamInfo( + mZed, mLeftCamInfoMsg, mRightCamInfoMsg, mLeftCamOptFrameId, + mRightCamOptFrameId); + fillCamInfo( + mZed, mLeftCamInfoRawMsg, mRightCamInfoRawMsg, mLeftCamOptFrameId, + mRightCamOptFrameId, true); + // <---- Camera Info messages + + initPublishers(); // Requires mZedRealCamModel available only after camera + // opening + initSubscribers(); + + // Disable AEC_AGC and Auto Whitebalance to trigger it if user set it to + // automatic + if (!mSvoMode && !mSimMode) { + mZed->setCameraSettings(sl::VIDEO_SETTINGS::AEC_AGC, 0); + mZed->setCameraSettings(sl::VIDEO_SETTINGS::WHITEBALANCE_AUTO, 0); + + // Lock on Positional Tracking mutex to avoid race conditions + std::lock_guard lock(mPtMutex); + + // Force parameters with a dummy grab + mZed->grab(); + } + + // Initialialized timestamp to avoid wrong initial data + // ----> Timestamp + if (mSvoMode) { + if (mUseSvoTimestamp) { + mFrameTimestamp = sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + + DEBUG_COMM("=========================================================*"); + DEBUG_STREAM_COMM("SVO Timestamp\t\t" << mFrameTimestamp.nanoseconds() << " nsec"); + DEBUG_STREAM_COMM( + "Current Timestamp\t" << + sl_tools::slTime2Ros( + mZed->getTimestamp( + sl::TIME_REFERENCE::CURRENT)).nanoseconds() << " nsec"); + DEBUG_COMM("=========================================================*"); + } else { + mFrameTimestamp = + sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::CURRENT)); + } + } else if (mSimMode) { + if (mUseSimTime) { + mFrameTimestamp = get_clock()->now(); + } else { + mFrameTimestamp = + sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } + } else { + mFrameTimestamp = + sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } + // <---- Timestamp + + // ----> Initialize Diagnostic statistics + mElabPeriodMean_sec = std::make_unique(mCamGrabFrameRate); + mGrabPeriodMean_sec = std::make_unique(mCamGrabFrameRate); + mVideoDepthPeriodMean_sec = + std::make_unique(mCamGrabFrameRate); + mVideoDepthElabMean_sec = + std::make_unique(mCamGrabFrameRate); + mPcPeriodMean_sec = std::make_unique(mCamGrabFrameRate); + mPcProcMean_sec = std::make_unique(mCamGrabFrameRate); + mObjDetPeriodMean_sec = std::make_unique(mCamGrabFrameRate); + mObjDetElabMean_sec = std::make_unique(mCamGrabFrameRate); + mBodyTrkPeriodMean_sec = + std::make_unique(mCamGrabFrameRate); + mBodyTrkElabMean_sec = std::make_unique(mCamGrabFrameRate); + mImuPeriodMean_sec = std::make_unique(20); + mBaroPeriodMean_sec = std::make_unique(20); + mMagPeriodMean_sec = std::make_unique(20); + mPubFusedCloudPeriodMean_sec = std::make_unique(mPcPubRate); + mPubOdomTF_sec = std::make_unique(mSensPubRate); + mPubPoseTF_sec = std::make_unique(mSensPubRate); + mPubImuTF_sec = std::make_unique(mSensPubRate); + mGnssFix_sec = std::make_unique(10); + // <---- Initialize Diagnostic statistics + + if (mGnssFusionEnabled) { + DEBUG_GNSS("Initialize Fusion module"); + + // ----> Retrieve GNSS to ZED transform + RCLCPP_INFO(get_logger(), "=== Initialize GNSS Offset ==="); + if (!mGnss2BaseTransfValid) { + getGnss2BaseTransform(); + } + + mGnssAntennaPose[0] = mGnss2BaseTransf.getOrigin().x(); + mGnssAntennaPose[1] = mGnss2BaseTransf.getOrigin().y(); + mGnssAntennaPose[2] = mGnss2BaseTransf.getOrigin().z(); + // <---- Retrieve GNSS to ZED transform + + // ----> Initialize Fusion module + + // Fusion parameters + mFusionInitParams.coordinate_system = ROS_COORDINATE_SYSTEM; + mFusionInitParams.coordinate_units = ROS_MEAS_UNITS; + mFusionInitParams.verbose = mVerbose != 0; + mFusionInitParams.output_performance_metrics = true; + mFusionInitParams.timeout_period_number = 20; + + // Fusion initialization + sl::FUSION_ERROR_CODE fus_err = mFusion.init(mFusionInitParams); + if (fus_err != sl::FUSION_ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error initializing the Fusion module: " + << sl::toString(fus_err).c_str() + << "."); + exit(EXIT_FAILURE); + } + DEBUG_GNSS(" Fusion params OK"); + + mFusionConfig = std::make_shared(); + + if (mSimMode) { + // TODO(Walter) Modify when support for streaming input is added in the + // SDK mFusionConfig->input_type.setFromStream(mSimAddr, mSimPort); + mFusionConfig->input_type.setFromSerialNumber(mCamSerialNumber); + mFusionConfig->communication_parameters.setForSharedMemory(); + } else if (mSvoMode) { + mFusionConfig->input_type.setFromSVOFile(mSvoFilepath.c_str()); + mFusionConfig->communication_parameters.setForSharedMemory(); + } else { + mFusionConfig->input_type.setFromSerialNumber(mCamSerialNumber); + mFusionConfig->communication_parameters.setForSharedMemory(); + } + mFusionConfig->serial_number = mCamSerialNumber; + mFusionConfig->pose = sl::Transform::identity(); + + DEBUG_GNSS(" Fusion communication params OK"); + + // Camera identifier + mCamUuid.sn = mCamSerialNumber; + + // Enable camera publishing to Fusion + mZed->startPublishing(mFusionConfig->communication_parameters); + DEBUG_GNSS(" Camera publishing OK"); + + // Fusion subscribe to camera data + fus_err = mFusion.subscribe( + mCamUuid, mFusionConfig->communication_parameters, mFusionConfig->pose); + if (fus_err != sl::FUSION_ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error initializing the Fusion module: " + << sl::toString(fus_err).c_str()); + exit(EXIT_FAILURE); + } + DEBUG_GNSS(" Fusion subscribing OK"); + DEBUG_GNSS("Fusion module ready"); + // <---- Initialize Fusion module + } + + // Init and start threads + initThreads(); + + return true; +} // namespace stereolabs + +void ZedCamera::closeCamera() +{ + std::lock_guard lock(mCloseCameraMutex); + if (mZed == nullptr) { + return; + } + + RCLCPP_INFO(get_logger(), "=== CLOSING CAMERA ==="); + + if (mPosTrackingStarted && !mAreaMemoryFilePath.empty() && + mSaveAreaMemoryOnClosing) + { + DEBUG_STREAM_COMM("Saving area memory on: " << mAreaMemoryFilePath); + saveAreaMemoryFile(mAreaMemoryFilePath); + DEBUG_STREAM_COMM("Saved area memory on: " << mAreaMemoryFilePath); + } + + mZed->close(); + mZed.reset(); + RCLCPP_INFO(get_logger(), "=== CAMERA CLOSED ==="); +} + +void ZedCamera::initThreads() +{ + // Start Heartbeat timer + startHeartbeatTimer(); + + // ----> Start CMOS Temperatures thread + if (!mSimMode && !sl_tools::isZED(mCamRealModel) && + !sl_tools::isZEDM(mCamRealModel)) + { + startTempPubTimer(); + } + // <---- Start CMOS Temperatures thread + + // ----> Start Sensors thread if not sync + if (!mSensCameraSync && !sl_tools::isZED(mCamRealModel)) { + mSensThread = std::thread(&ZedCamera::threadFunc_pubSensorsData, this); + } + // <---- Start Sensors thread if not sync + + // ----> Start Video/Depth thread + mVdDataReady = false; + mVdThread = std::thread(&ZedCamera::threadFunc_videoDepthElab, this); + // <---- Start Video/Depth thread + + // ----> Start Pointcloud thread + if (!mDepthDisabled) { + mPcDataReady = false; + mPcThread = std::thread(&ZedCamera::threadFunc_pointcloudElab, this); + } + // <---- Start Pointcloud thread + + // Start grab thread + mGrabThread = std::thread(&ZedCamera::threadFunc_zedGrab, this); +} + +void ZedCamera::startHeartbeatTimer() +{ + if (mHeartbeatTimer != nullptr) { + mHeartbeatTimer->cancel(); + } + + std::chrono::milliseconds pubPeriod_msec(HEARTBEAT_INTERVAL_MS); + mHeartbeatTimer = create_wall_timer( + std::chrono::duration_cast(pubPeriod_msec), + std::bind(&ZedCamera::callback_pubHeartbeat, this)); +} + +void ZedCamera::startTempPubTimer() +{ + if (mTempPubTimer != nullptr) { + mTempPubTimer->cancel(); + } + + std::chrono::milliseconds pubPeriod_msec(TEMP_PUB_INTERVAL_MS); + mTempPubTimer = create_wall_timer( + std::chrono::duration_cast(pubPeriod_msec), + std::bind(&ZedCamera::callback_pubTemp, this)); +} + +void ZedCamera::startFusedPcTimer(double fusedPcRate) +{ + if (mFusedPcTimer != nullptr) { + mFusedPcTimer->cancel(); + } + + std::chrono::milliseconds pubPeriod_msec( + static_cast(1000.0 / (fusedPcRate))); + mFusedPcTimer = create_wall_timer( + std::chrono::duration_cast(pubPeriod_msec), + std::bind(&ZedCamera::callback_pubFusedPc, this)); +} + +void ZedCamera::startPathPubTimer(double pathTimerRate) +{ + if (mPathTimer != nullptr) { + mPathTimer->cancel(); + } + + DEBUG_PT("Starting path pub. timer"); + + if (pathTimerRate > 0) { + std::chrono::milliseconds pubPeriod_msec( + static_cast(1000.0 / (pathTimerRate))); + mPathTimer = create_wall_timer( + std::chrono::duration_cast(pubPeriod_msec), + std::bind(&ZedCamera::callback_pubPaths, this)); + + if (mOdomPath.size() == 0 && mPosePath.size() == 0) { + if (mPathMaxCount != -1) { + DEBUG_STREAM_PT("Path vectors reserved " << mPathMaxCount << " poses."); + mOdomPath.reserve(mPathMaxCount); + mPosePath.reserve(mPathMaxCount); + + DEBUG_STREAM_PT( + "Path vector sizes: " << mOdomPath.size() << " " + << mPosePath.size()); + } + } + } else { + mOdomPath.clear(); + mPosePath.clear(); + mPathTimer->cancel(); + RCLCPP_INFO_STREAM( + get_logger(), "Path topics not published -> Pub. rate: " + << pathTimerRate << " Hz"); + } +} + +bool ZedCamera::startPosTracking() +{ + // Lock on Positional Tracking mutex to avoid race conditions + std::lock_guard lock(mPtMutex); + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is + // disabled + if (mDepthDisabled && mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (mDepthDisabled) { +#endif + RCLCPP_WARN( + get_logger(), + "Cannot start Positional Tracking if Depth processing is " + "disabled (except for GEN_3 mode)."); + return false; + } + + if (mZed && mZed->isPositionalTrackingEnabled()) { + if (!mAreaMemoryFilePath.empty() && mSaveAreaMemoryOnClosing) { + mZed->disablePositionalTracking(mAreaMemoryFilePath.c_str()); + RCLCPP_INFO( + get_logger(), + "Area memory updated before restarting the Positional " + "Tracking module."); + } else { + mZed->disablePositionalTracking(); + } + } + + RCLCPP_INFO(get_logger(), "=== Starting Positional Tracking ==="); + + RCLCPP_INFO(get_logger(), " * Waiting for valid static transformations..."); + + bool transformOk = false; + double elapsed = 0.0; + mPosTrackingReady = false; + mGnssInitGood = false; + + // auto start = std::chrono::high_resolution_clock::now(); + + sl_tools::StopWatch stopWatch(get_clock()); + + do { + transformOk = // true; + setPose( + mInitialBasePose[0], mInitialBasePose[1], mInitialBasePose[2], + mInitialBasePose[3], mInitialBasePose[4], + mInitialBasePose[5]); + + elapsed = stopWatch.toc(); + + rclcpp::sleep_for(1ms); + + if (elapsed > 10000) { + RCLCPP_WARN( + get_logger(), + " !!! Failed to get static transforms. Is the " + "'ROBOT STATE PUBLISHER' node correctly " + "working? "); + break; + } + } while (transformOk == false); + + if (transformOk) { + DEBUG_STREAM_PT( + "Time required to get valid static transforms: " + << elapsed / 1000. << " sec"); + } + + RCLCPP_INFO( + get_logger(), + "Initial ZED left camera pose (ZED pos. tracking): "); + RCLCPP_INFO( + get_logger(), " * T: [%g,%g,%g]", mInitialPoseSl.getTranslation().x, + mInitialPoseSl.getTranslation().y, mInitialPoseSl.getTranslation().z); + RCLCPP_INFO( + get_logger(), " * Q: [%g,%g,%g,%g]", mInitialPoseSl.getOrientation().ox, + mInitialPoseSl.getOrientation().oy, mInitialPoseSl.getOrientation().oz, + mInitialPoseSl.getOrientation().ow); + + // Tracking parameters + sl::PositionalTrackingParameters ptParams; + + mPoseSmoothing = false; // Always false. Pose Smoothing is to be enabled + // only for VR/AR applications + + ptParams.enable_pose_smoothing = mPoseSmoothing; + ptParams.enable_area_memory = mAreaMemory; + ptParams.area_file_path = + (mAreaFileExists ? mAreaMemoryFilePath.c_str() : ""); + ptParams.enable_localization_only = mLocalizationOnly; + ptParams.enable_imu_fusion = mImuFusion; + ptParams.initial_world_transform = mInitialPoseSl; + ptParams.set_floor_as_origin = mFloorAlignment; + ptParams.depth_min_range = mPosTrackDepthMinRange; + ptParams.set_as_static = mSetAsStatic; + ptParams.set_gravity_as_origin = mSetGravityAsOrigin; + ptParams.mode = mPosTrkMode; + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + if (mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { + ptParams.enable_2d_ground_mode = mTwoDMode; + } else { + ptParams.enable_2d_ground_mode = false; + } +#endif + + if (_debugPosTracking) { + DEBUG_PT(" * Positional Tracking parameters:"); + sl::String json; + ptParams.encode(json); + DEBUG_PT(json.c_str()); + } + + sl::ERROR_CODE err = mZed->enablePositionalTracking(ptParams); + + if (err != sl::ERROR_CODE::SUCCESS) { + mPosTrackingStarted = false; + RCLCPP_WARN( + get_logger(), "Pos. Tracking not started: %s", + sl::toString(err).c_str()); + return false; + } + + DEBUG_PT("Positional Tracking started"); + + // ----> Enable Fusion Positional Tracking if required + if (mGnssFusionEnabled && err == sl::ERROR_CODE::SUCCESS) { + mMap2UtmTransfValid = false; + + sl::PositionalTrackingFusionParameters fusion_params; + fusion_params.enable_GNSS_fusion = mGnssFusionEnabled; + + sl::GNSSCalibrationParameters gnss_par; + gnss_par.target_yaw_uncertainty = mGnssTargetYawUncertainty; + gnss_par.enable_translation_uncertainty_target = + mGnssEnableTranslationUncertaintyTarget; + gnss_par.target_translation_uncertainty = mGnssTargetTranslationUncertainty; + gnss_par.enable_reinitialization = mGnssEnableReinitialization; + gnss_par.gnss_vio_reinit_threshold = mGnssVioReinitThreshold; + gnss_par.enable_rolling_calibration = mGnssEnableRollingCalibration; + gnss_par.gnss_antenna_position = mGnssAntennaPose; + + DEBUG_STREAM_GNSS( + "GNSS antenna pose in ZED SDK coordinate: " + << mGnssAntennaPose[0] << "," << mGnssAntennaPose[1] + << "," << mGnssAntennaPose[2]); + + fusion_params.gnss_calibration_parameters = gnss_par; + + sl::FUSION_ERROR_CODE fus_err = + mFusion.enablePositionalTracking(fusion_params); + + if (fus_err != sl::FUSION_ERROR_CODE::SUCCESS) { + mPosTrackingStarted = false; + RCLCPP_WARN( + get_logger(), "Fusion Pos. Tracking not started: %s", + sl::toString(fus_err).c_str()); + mZed->disablePositionalTracking(); + return false; + } + DEBUG_GNSS("Fusion Positional Tracking started"); + } + // <---- Enable Fusion Positional Tracking if required + + mPoseLocked = false; + mPoseLockCount = 0; + mPosTrackingStarted = true; + + startPathPubTimer(mPathPubRate); + + return mPosTrackingStarted; +} + +bool ZedCamera::saveAreaMemoryFile(const std::string & filePath) +{ + if (!mZed) { + RCLCPP_WARN(get_logger(), "ZED camera is not initialized"); + return false; + } + + if (!mAreaMemory) { + RCLCPP_WARN( + get_logger(), + "Failed to save area memory: 'Area Memory was not enabled'"); + return false; + } + + RCLCPP_INFO_STREAM(get_logger(), "Saving area memory to: '" << filePath << "' ..."); + sl::ERROR_CODE err = mZed->saveAreaMap(filePath.c_str()); + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Failed to save area memory: '" + << sl::toString(err) << "'"); + return false; + } + + auto export_state = sl::AREA_EXPORTING_STATE::RUNNING; + while (export_state == sl::AREA_EXPORTING_STATE::RUNNING) { + export_state = mZed->getAreaExportState(); + sl::sleep_ms(5); + } + + if (export_state != sl::AREA_EXPORTING_STATE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Failed to save area memory: '" + << sl::toString(export_state) << "'"); + return false; + } + + RCLCPP_INFO(get_logger(), "... Area memory saved successfully"); + return true; +} + +bool ZedCamera::start3dMapping() +{ + DEBUG_MAP("start3dMapping"); + if (mDepthDisabled) { + RCLCPP_WARN( + get_logger(), + "Cannot start 3D Mapping if Depth processing is disabled"); + return false; + } + + if (mSpatialMappingRunning) { + RCLCPP_WARN( + get_logger(), + "Cannot start 3D Mapping. The module is already running!"); + return false; + } + + bool required = mMappingEnabled; + + if (!required) { + return false; + } + + RCLCPP_INFO_STREAM(get_logger(), "=== Starting Spatial Mapping ==="); + + sl::SpatialMappingParameters params; + params.map_type = + sl::SpatialMappingParameters::SPATIAL_MAP_TYPE::FUSED_POINT_CLOUD; + params.use_chunk_only = true; + + sl::SpatialMappingParameters spMapPar; + + float lRes = spMapPar.allowed_resolution.first; + float hRes = spMapPar.allowed_resolution.second; + + if (mMappingRes < lRes) { + RCLCPP_WARN_STREAM( + get_logger(), + "'mapping.resolution' value (" + << mMappingRes + << " m) is lower than the allowed resolution " + "values. Fixed automatically"); + mMappingRes = lRes; + } + if (mMappingRes > hRes) { + RCLCPP_WARN_STREAM( + get_logger(), + "'mapping.resolution' value (" + << mMappingRes + << " m) is higher than the allowed resolution " + "values. Fixed automatically"); + mMappingRes = hRes; + } + + params.resolution_meter = mMappingRes; + + float lRng = spMapPar.allowed_range.first; + float hRng = spMapPar.allowed_range.second; + + if (mMappingRangeMax < 0) { + mMappingRangeMax = + sl::SpatialMappingParameters::getRecommendedRange(mMappingRes, *mZed.get()); + RCLCPP_INFO_STREAM( + get_logger(), "Mapping: max range set to " + << mMappingRangeMax + << " m for a resolution of " + << mMappingRes << " m"); + } else if (mMappingRangeMax < lRng) { + RCLCPP_WARN_STREAM( + get_logger(), "'mapping.max_mapping_range_m' value (" + << mMappingRangeMax + << " m) is lower than the allowed " + "resolution values. Fixed " + "automatically"); + mMappingRangeMax = lRng; + } else if (mMappingRangeMax > hRng) { + RCLCPP_WARN_STREAM( + get_logger(), "'mapping.max_mapping_range_m' value (" + << mMappingRangeMax + << " m) is higher than the allowed " + "resolution values. Fixed " + "automatically"); + mMappingRangeMax = hRng; + } + + params.range_meter = mMappingRangeMax; + + sl::ERROR_CODE err = mZed->enableSpatialMapping(params); + + if (err == sl::ERROR_CODE::SUCCESS) { + if (mPubFusedCloud == nullptr) { +#ifdef FOUND_POINT_CLOUD_TRANSPORT + mPubFusedCloud = point_cloud_transport::create_publisher( + shared_from_this(), mPointcloudFusedTopic, mQos.get_rmw_qos_profile(), + mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic " + << mPubFusedCloud.getTopic() + << " @ " << mFusedPcPubRate + << " Hz"); +#else + mPubFusedCloud = create_publisher( + mPointcloudFusedTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), "Advertised on topic " + << mPubFusedCloud->get_topic_name() + << " @ " << mFusedPcPubRate + << " Hz"); +#endif + } + + mSpatialMappingRunning = true; + + startFusedPcTimer(mFusedPcPubRate); + + RCLCPP_INFO_STREAM( + get_logger(), + " * Resolution: " << params.resolution_meter << " m"); + RCLCPP_INFO_STREAM( + get_logger(), + " * Max Mapping Range: " << params.range_meter << " m"); + RCLCPP_INFO_STREAM( + get_logger(), " * Map point cloud publishing rate: " + << mFusedPcPubRate << " Hz"); + + return true; + } else { + mSpatialMappingRunning = false; + if (mFusedPcTimer) { + mFusedPcTimer->cancel(); + } + + RCLCPP_WARN( + get_logger(), "Mapping not activated: %s", + sl::toString(err).c_str()); + + return false; + } +} + +void ZedCamera::stop3dMapping() +{ + if (mFusedPcTimer) { + mFusedPcTimer->cancel(); + } + + mSpatialMappingRunning = false; + mMappingEnabled = false; + + mZed->disableSpatialMapping(); + + RCLCPP_INFO(get_logger(), "=== Spatial Mapping stopped ==="); +} + +bool ZedCamera::startSvoRecording(std::string & errMsg) +{ + sl::RecordingParameters params; + + params.bitrate = mSvoRecBitrate; + params.compression_mode = mSvoRecCompression; + params.target_framerate = mSvoRecFramerate; + params.transcode_streaming_input = mSvoRecTranscode; + params.video_filename = mSvoRecFilename.c_str(); + + sl::ERROR_CODE err = mZed->enableRecording(params); + errMsg = sl::toString(err); + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Error starting SVO recording: " << errMsg); + return false; + } + + mRecording = true; + + return true; +} + +void ZedCamera::stopSvoRecording() +{ + if (mRecording) { + mRecording = false; + mZed->disableRecording(); + } +} + +void ZedCamera::initTransforms() +{ + // According to REP 105 -> http://www.ros.org/reps/rep-0105.html + + // camera_link <- odom <- map + // ^ | + // | | + // --------------------- + + // ----> Dynamic transforms + mOdom2BaseTransf.setIdentity(); // broadcasted if `publish_tf` is true + mMap2OdomTransf.setIdentity(); // broadcasted if `publish_map_tf` is true + mMap2BaseTransf.setIdentity(); // used internally, but not broadcasted + mMap2UtmTransf.setIdentity(); // broadcasted if GNSS Fusion is enabled + // <---- Dynamic transforms +} + +bool ZedCamera::getCamera2BaseTransform() +{ + DEBUG_STREAM_TF( + "Getting static TF from '" << mCenterFrameId.c_str() + << "' to '" << mBaseFrameId.c_str() + << "'"); + + mCamera2BaseTransfValid = false; + + // ----> Static transforms + // Sensor to Base link + try { + // Save the transformation + geometry_msgs::msg::TransformStamped c2b = mTfBuffer->lookupTransform( + mCenterFrameId, mBaseFrameId, TIMEZERO_SYS, rclcpp::Duration(1, 0)); + + // Get the TF2 transformation + // tf2::fromMsg(c2b.transform, mCamera2BaseTransf); + geometry_msgs::msg::Transform in = c2b.transform; + mCamera2BaseTransf.setOrigin( + tf2::Vector3(in.translation.x, in.translation.y, in.translation.z)); + // w at the end in the constructor + mCamera2BaseTransf.setRotation( + tf2::Quaternion( + in.rotation.x, in.rotation.y, in.rotation.z, in.rotation.w)); + + double roll, pitch, yaw; + tf2::Matrix3x3(mCamera2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + RCLCPP_INFO( + get_logger(), + " Static transform Camera Center to Base [%s -> %s]", + mCenterFrameId.c_str(), mBaseFrameId.c_str()); + RCLCPP_INFO( + get_logger(), " * Translation: {%.3f,%.3f,%.3f}", + mCamera2BaseTransf.getOrigin().x(), + mCamera2BaseTransf.getOrigin().y(), + mCamera2BaseTransf.getOrigin().z()); + RCLCPP_INFO( + get_logger(), " * Rotation: {%.3f,%.3f,%.3f}", roll * RAD2DEG, + pitch * RAD2DEG, yaw * RAD2DEG); + } catch (tf2::TransformException & ex) { + if (!mCamera2BaseFirstErr) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Transform error: %s", ex.what()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "The tf from '%s' to '%s' is not available.", + mCenterFrameId.c_str(), mBaseFrameId.c_str()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Note: one of the possible cause of the problem is the absence of an " + "instance " + "of the `robot_state_publisher` node publishing the correct static " + "TF transformations " + "or a modified URDF not correctly reproducing the ZED " + "TF chain '%s' -> '%s' -> '%s'", + mBaseFrameId.c_str(), mCenterFrameId.c_str(), mDepthFrameId.c_str()); + mCamera2BaseFirstErr = false; + } + + mCamera2BaseTransf.setIdentity(); + return false; + } + // <---- Static transforms + + mCamera2BaseTransfValid = true; + return true; +} + +bool ZedCamera::getSens2CameraTransform() +{ + DEBUG_STREAM_TF( + "Getting static TF from '" + << mDepthFrameId.c_str() << "' to '" << mCenterFrameId.c_str() + << "'"); + + mSensor2CameraTransfValid = false; + + // ----> Static transforms + // Sensor to Camera Center + try { + // Save the transformation + geometry_msgs::msg::TransformStamped s2c = mTfBuffer->lookupTransform( + mDepthFrameId, mCenterFrameId, TIMEZERO_SYS, rclcpp::Duration(1, 0)); + + // Get the TF2 transformation + // tf2::fromMsg(s2c.transform, mSensor2CameraTransf); + geometry_msgs::msg::Transform in = s2c.transform; + mSensor2CameraTransf.setOrigin( + tf2::Vector3(in.translation.x, in.translation.y, in.translation.z)); + // w at the end in the constructor + mSensor2CameraTransf.setRotation( + tf2::Quaternion( + in.rotation.x, in.rotation.y, in.rotation.z, in.rotation.w)); + + double roll, pitch, yaw; + tf2::Matrix3x3(mSensor2CameraTransf.getRotation()).getRPY(roll, pitch, yaw); + + RCLCPP_INFO( + get_logger(), + " Static transform ref. CMOS Sensor to Camera Center [%s -> %s]", + mDepthFrameId.c_str(), mCenterFrameId.c_str()); + RCLCPP_INFO( + get_logger(), " * Translation: {%.3f,%.3f,%.3f}", + mSensor2CameraTransf.getOrigin().x(), + mSensor2CameraTransf.getOrigin().y(), + mSensor2CameraTransf.getOrigin().z()); + RCLCPP_INFO( + get_logger(), " * Rotation: {%.3f,%.3f,%.3f}", roll * RAD2DEG, + pitch * RAD2DEG, yaw * RAD2DEG); + } catch (tf2::TransformException & ex) { + if (!mSensor2CameraTransfFirstErr) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Transform error: %s", ex.what()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "The tf from '%s' to '%s' is not available.", + mDepthFrameId.c_str(), mCenterFrameId.c_str()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Note: one of the possible cause of the problem is the absence of an " + "instance " + "of the `robot_state_publisher` node publishing the correct static " + "TF transformations " + "or a modified URDF not correctly reproducing the ZED " + "TF chain '%s' -> '%s' -> '%s'", + mBaseFrameId.c_str(), mCenterFrameId.c_str(), mDepthFrameId.c_str()); + mSensor2CameraTransfFirstErr = false; + } + + mSensor2CameraTransf.setIdentity(); + return false; + } + // <---- Static transforms + + mSensor2CameraTransfValid = true; + return true; +} + +bool ZedCamera::getSens2BaseTransform() +{ + DEBUG_STREAM_TF( + "Getting static TF from '" << mDepthFrameId.c_str() + << "' to '" << mBaseFrameId.c_str() + << "'"); + + mSensor2BaseTransfValid = false; + + // ----> Static transforms + // Sensor to Base link + try { + // Save the transformation + geometry_msgs::msg::TransformStamped s2b = mTfBuffer->lookupTransform( + mDepthFrameId, mBaseFrameId, TIMEZERO_SYS, rclcpp::Duration(1, 0)); + + // Get the TF2 transformation + // tf2::fromMsg(s2b.transform, mSensor2BaseTransf); + geometry_msgs::msg::Transform in = s2b.transform; + mSensor2BaseTransf.setOrigin( + tf2::Vector3(in.translation.x, in.translation.y, in.translation.z)); + // w at the end in the constructor + mSensor2BaseTransf.setRotation( + tf2::Quaternion( + in.rotation.x, in.rotation.y, in.rotation.z, in.rotation.w)); + + double roll, pitch, yaw; + tf2::Matrix3x3(mSensor2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + RCLCPP_INFO( + get_logger(), + " Static transform ref. CMOS Sensor to Base [%s -> %s]", + mDepthFrameId.c_str(), mBaseFrameId.c_str()); + RCLCPP_INFO( + get_logger(), " * Translation: {%.3f,%.3f,%.3f}", + mSensor2BaseTransf.getOrigin().x(), + mSensor2BaseTransf.getOrigin().y(), + mSensor2BaseTransf.getOrigin().z()); + RCLCPP_INFO( + get_logger(), " * Rotation: {%.3f,%.3f,%.3f}", roll * RAD2DEG, + pitch * RAD2DEG, yaw * RAD2DEG); + } catch (tf2::TransformException & ex) { + if (!mSensor2BaseTransfFirstErr) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Transform error: %s", ex.what()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "The tf from '%s' to '%s' is not available.", + mDepthFrameId.c_str(), mBaseFrameId.c_str()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Note: one of the possible cause of the problem is the absense of an " + "instance " + "of the `robot_state_publisher` node publishing the correct static " + "TF transformations " + "or a modified URDF not correctly reproducing the ZED " + "TF chain '%s' -> '%s' -> '%s'", + mBaseFrameId.c_str(), mCenterFrameId.c_str(), mDepthFrameId.c_str()); + mSensor2BaseTransfFirstErr = false; + } + + mSensor2BaseTransf.setIdentity(); + return false; + } + + // <---- Static transforms + + mSensor2BaseTransfValid = true; + return true; +} + +bool ZedCamera::getGnss2BaseTransform() +{ + DEBUG_GNSS( + "Getting static TF from '%s' to '%s'", mGnssFrameId.c_str(), + mBaseFrameId.c_str()); + + mGnss2BaseTransfValid = false; + + // ----> Static transforms + // Sensor to Base link + try { + // Save the transformation + geometry_msgs::msg::TransformStamped g2b = mTfBuffer->lookupTransform( + mGnssFrameId, mBaseFrameId, TIMEZERO_SYS, rclcpp::Duration(1, 0)); + + // Get the TF2 transformation + geometry_msgs::msg::Transform in = g2b.transform; + mGnss2BaseTransf.setOrigin( + tf2::Vector3(in.translation.x, in.translation.y, in.translation.z)); + // w at the end in the constructor + mGnss2BaseTransf.setRotation( + tf2::Quaternion( + in.rotation.x, in.rotation.y, + in.rotation.z, in.rotation.w)); + + double roll, pitch, yaw; + tf2::Matrix3x3(mGnss2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + RCLCPP_INFO( + get_logger(), + " Static transform GNSS Antenna to Camera Base [%s -> %s]", + mGnssFrameId.c_str(), mBaseFrameId.c_str()); + RCLCPP_INFO( + get_logger(), " * Translation: {%.3f,%.3f,%.3f}", + mGnss2BaseTransf.getOrigin().x(), + mGnss2BaseTransf.getOrigin().y(), + mGnss2BaseTransf.getOrigin().z()); + RCLCPP_INFO( + get_logger(), " * Rotation: {%.3f,%.3f,%.3f}", roll * RAD2DEG, + pitch * RAD2DEG, yaw * RAD2DEG); + } catch (tf2::TransformException & ex) { + if (!mGnss2BaseTransfFirstErr) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + DEBUG_STREAM_THROTTLE_GNSS(1000.0, "Transform error: " << ex.what()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "The tf from '%s' to '%s' is not available.", + mGnssFrameId.c_str(), mBaseFrameId.c_str()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Note: one of the possible cause of the problem is the absense of an " + "instance " + "of the `robot_state_publisher` node publishing the correct static " + "TF transformations " + "or a modified URDF not correctly reproducing the " + "TF chain '%s' -> '%s'", + mBaseFrameId.c_str(), mGnssFrameId.c_str()); + mGnss2BaseTransfFirstErr = false; + } + + mGnss2BaseTransf.setIdentity(); + return false; + } + // <---- Static transforms + + mGnss2BaseTransfValid = true; + return true; +} + +bool ZedCamera::setPose( + float xt, float yt, float zt, float rr, float pr, + float yr) +{ + initTransforms(); + + if (!mSensor2BaseTransfValid) { + getSens2BaseTransform(); + } + + if (!mSensor2CameraTransfValid) { + getSens2CameraTransform(); + } + + if (!mCamera2BaseTransfValid) { + getCamera2BaseTransform(); + } + + // Apply Base to sensor transform + tf2::Transform initPose; + tf2::Vector3 origin(xt, yt, zt); + initPose.setOrigin(origin); + tf2::Quaternion quat; + quat.setRPY(rr, pr, yr); + initPose.setRotation(quat); + + initPose = initPose * mSensor2BaseTransf.inverse(); + + // SL pose + sl::float3 t_vec; + t_vec[0] = initPose.getOrigin().x(); + t_vec[1] = initPose.getOrigin().y(); + t_vec[2] = initPose.getOrigin().z(); + + sl::float4 q_vec; + q_vec[0] = initPose.getRotation().x(); + q_vec[1] = initPose.getRotation().y(); + q_vec[2] = initPose.getRotation().z(); + q_vec[3] = initPose.getRotation().w(); + + sl::Translation trasl(t_vec); + sl::Orientation orient(q_vec); + mInitialPoseSl.setTranslation(trasl); + mInitialPoseSl.setOrientation(orient); + + return mSensor2BaseTransfValid & mSensor2CameraTransfValid & + mCamera2BaseTransfValid; +} + +void ZedCamera::publishImuFrameAndTopic() +{ + if (!mPublishSensImuTransf && !mPublishImuTF) { + return; + } + + if (!mUsingIPC && mStaticImuTfPublished) { + DEBUG_ONCE_TF("Static Imu TF and Transient Local message already published"); + return; + } + + sl::Orientation sl_rot = mSlCamImuTransf.getOrientation(); + sl::Translation sl_tr = mSlCamImuTransf.getTranslation(); + + auto cameraImuTransfMgs = std::make_unique(); + + cameraImuTransfMgs->header.stamp = get_clock()->now(); + + cameraImuTransfMgs->header.frame_id = mLeftCamFrameId; + cameraImuTransfMgs->child_frame_id = mImuFrameId; + + cameraImuTransfMgs->transform.rotation.x = sl_rot.ox; + cameraImuTransfMgs->transform.rotation.y = sl_rot.oy; + cameraImuTransfMgs->transform.rotation.z = sl_rot.oz; + cameraImuTransfMgs->transform.rotation.w = sl_rot.ow; + + cameraImuTransfMgs->transform.translation.x = sl_tr.x; + cameraImuTransfMgs->transform.translation.y = sl_tr.y; + cameraImuTransfMgs->transform.translation.z = sl_tr.z; + + try { + if (mPubCamImuTransf) { + mPubCamImuTransf->publish(std::move(cameraImuTransfMgs)); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + + // Publish IMU TF as static TF + if (!mPublishImuTF) { + return; + } + + // ----> Publish TF + // RCLCPP_INFO(get_logger(), "Broadcasting Camera-IMU TF "); + + geometry_msgs::msg::TransformStamped transformStamped; + + transformStamped.header.stamp = + get_clock()->now() + rclcpp::Duration(0, mTfOffset * 1e9); + + transformStamped.header.frame_id = mLeftCamFrameId; + transformStamped.child_frame_id = mImuFrameId; + + transformStamped.transform.rotation.x = sl_rot.ox; + transformStamped.transform.rotation.y = sl_rot.oy; + transformStamped.transform.rotation.z = sl_rot.oz; + transformStamped.transform.rotation.w = sl_rot.ow; + + transformStamped.transform.translation.x = sl_tr.x; + transformStamped.transform.translation.y = sl_tr.y; + transformStamped.transform.translation.z = sl_tr.z; + + if (mUsingIPC) { + mTfBroadcaster->sendTransform(transformStamped); + DEBUG_STREAM_TF( + "Broadcasted new IMU dynamic transform: " + << transformStamped.header.frame_id << " -> " << transformStamped.child_frame_id); + } else { + mStaticTfBroadcaster->sendTransform(transformStamped); + DEBUG_STREAM_TF( + "Broadcasted new IMU static transform: " + << transformStamped.header.frame_id << " -> " << transformStamped.child_frame_id); + } + // <---- Publish TF + + // IMU TF publishing diagnostic + double elapsed_sec = mImuTfFreqTimer.toc(); + mPubImuTF_sec->addValue(elapsed_sec); + mImuTfFreqTimer.tic(); + + // Debug info + if (_debugTf) { + double roll, pitch, yaw; + tf2::Matrix3x3( + tf2::Quaternion( + transformStamped.transform.rotation.x, + transformStamped.transform.rotation.y, + transformStamped.transform.rotation.z, + transformStamped.transform.rotation.w)) + .getRPY(roll, pitch, yaw); + DEBUG_STREAM_TF( + " - Broadcasted IMU static transform: " + "TF [" + << transformStamped.header.frame_id << " -> " + << transformStamped.child_frame_id << "] Position: (" + << transformStamped.transform.translation.x << ", " + << transformStamped.transform.translation.y << ", " + << transformStamped.transform.translation.z + << ") - Orientation RPY: (" << roll * RAD2DEG << ", " + << pitch * RAD2DEG << ", " << yaw * RAD2DEG << ")"); + } + + // At the end + mStaticImuTfPublished = true; +} + +void ZedCamera::threadFunc_zedGrab() +{ + DEBUG_STREAM_COMM("Grab thread started"); + + // Set the name of the zedGrab thread for easier identification in + // system monitors + pthread_setname_np(pthread_self(), (get_name() + std::string("_zedGrab")).c_str()); + + // ----> Advanced thread settings + if (mChangeThreadSched) { + DEBUG_STREAM_ADV("Grab thread settings"); + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * Default GRAB thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + + if (mThreadSchedPolicy == "SCHED_OTHER") { + sched_param par; + par.sched_priority = 0; + if (pthread_setschedparam(pthread_self(), SCHED_OTHER, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_BATCH") { + sched_param par; + par.sched_priority = 0; + if (pthread_setschedparam(pthread_self(), SCHED_BATCH, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_FIFO") { + sched_param par; + par.sched_priority = mThreadPrioGrab; + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_RR") { + sched_param par; + par.sched_priority = mThreadPrioGrab; + if (pthread_setschedparam(pthread_self(), SCHED_RR, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - Policy not supported"); + } + + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * New GRAB thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + } + // <---- Advanced thread settings + + mFrameCount = 0; + + // ----> Grab Runtime parameters + mRunParams.enable_depth = false; + mRunParams.measure3D_reference_frame = sl::REFERENCE_FRAME::CAMERA; + mRunParams.remove_saturated_areas = mRemoveSatAreas; + // <---- Grab Runtime parameters + + // Infinite grab thread + while (1) { + try { + RCLCPP_INFO_STREAM_ONCE(get_logger(), "=== " << mCameraName << " started ==="); + + // ----> Interruption check + DEBUG_STREAM_GRAB("Grab thread: checking for interruption"); + if (!rclcpp::ok()) { + mThreadStop = true; + DEBUG_STREAM_COMM("Ctrl+C received: stopping grab thread"); + break; + } + + if (mThreadStop) { + DEBUG_STREAM_COMM("Grab thread stopped"); + break; + } + // <---- Interruption check + + if (mSvoMode && mSvoPause) { + if (!mGrabOnce) { + rclcpp::sleep_for(100ms); +#ifdef USE_SVO_REALTIME_PAUSE + // Lock on Positional Tracking mutex to avoid race conditions + std::lock_guard lock(mPtMutex); + + // Dummy grab + mZed->grab(); + #endif + continue; + } else { + mGrabOnce = false; // Reset the flag and grab once + } + } + + if (mUseSimTime && !mClockAvailable) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 5000.0, + "Waiting for a valid simulation time on the '/clock' topic..."); + rclcpp::sleep_for(1ms); + continue; + } + + sl_tools::StopWatch grabElabTimer(get_clock()); + + // ----> Apply depth settings + DEBUG_STREAM_GRAB("Grab thread: applying depth settings"); + applyDepthSettings(); + // <---- Apply depth settings + + // ----> Apply video dynamic parameters + if (!mSimMode && !mSvoMode) { + DEBUG_STREAM_GRAB("Grab thread: applying video settings"); + applyVideoSettings(); + } + // <---- Apply video dynamic parameters + + // ----> Check for Positional Tracking requirement + DEBUG_STREAM_GRAB( + "Grab thread: checking Positional Tracking requirement"); + if (isPosTrackingRequired() && !mPosTrackingStarted) { + static int pt_err_count = 0; + if (!startPosTracking()) { + if (++pt_err_count >= 3) { + RCLCPP_FATAL( + get_logger(), + "It's not possible to enable the required Positional " + "Tracking module."); + exit(EXIT_FAILURE); + } + } else { + pt_err_count = 0; + } + } + + if (mGnssFusionEnabled && !mGnssFixValid) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 5000.0, + " * Waiting for the first valid GNSS fix..."); + } + // ----> Check for Positional Tracking requirement + + if (!mDepthDisabled) { + // ----> Check for Spatial Mapping requirement + + DEBUG_STREAM_GRAB("Grab thread: checking Spatial Mapping requirement"); + { + std::lock_guard lock(mMappingMutex); + if (mMappingEnabled && !mSpatialMappingRunning) { + start3dMapping(); + } + if (!mMappingEnabled && mSpatialMappingRunning) { + stop3dMapping(); + } + } + + // <---- Check for Spatial Mapping requirement + + // ----> Check for Object Detection requirement + DEBUG_STREAM_GRAB("Grab thread: checking Object Detection requirement"); + { + std::lock_guard lock(mObjDetMutex); + if (mObjDetEnabled && !mObjDetRunning) { + startObjDetect(); + if (!sl_tools::isObjDetAvailable(mCamRealModel)) { + mObjDetEnabled = false; + } + } + } + // ----> Check for Object Detection requirement + + // ----> Check for Body Tracking requirement + DEBUG_STREAM_GRAB("Grab thread: checking Body Tracking requirement"); + { + std::lock_guard lock(mBodyTrkMutex); + if (mBodyTrkEnabled && !mBodyTrkRunning) { + startBodyTracking(); + if (!sl_tools::isObjDetAvailable(mCamRealModel)) { + mBodyTrkEnabled = false; + } + } + } + // ----> Check for Object Detection requirement + } + + // ----> Grab freq calculation + double elapsed_sec = mGrabFreqTimer.toc(); + mGrabPeriodMean_sec->addValue(elapsed_sec); + mGrabFreqTimer.tic(); + + // RCLCPP_INFO_STREAM(get_logger(), "Grab period: " + // << mGrabPeriodMean_sec->getAvg() / 1e6 + // << " Freq: " << 1e6 / mGrabPeriodMean_usec->getAvg()); + // <---- Grab freq calculation + + // ----> Publish SVO Status information + if (mSvoMode) { + publishSvoStatus(mFrameTimestamp.nanoseconds()); + } + // <---- Publish SVO Status information + + // Lock on Positional Tracking mutex to avoid race conditions + DEBUG_STREAM_GRAB("Grab thread: locking PT mutex for grab"); + std::lock_guard lock(mPtMutex); + + // Start processing timer for diagnostic + grabElabTimer.tic(); + + // ZED grab + DEBUG_STREAM_GRAB("Grab thread: grabbing frame #" << mFrameCount); + + // ----> Params Debug info + if (_debugGrab) { + sl::String json; + mRunParams.encode(json); + DEBUG_STREAM_GRAB( + "Grab thread: Grab parameters: " << std::string(json)); + + mInitParams.encode(json); + DEBUG_STREAM_GRAB( + "Grab thread: Init parameters: " << std::string(json)); + } + // <---- Params Debug info + + if (isDepthRequired() || isPosTrackingRequired()) { + DEBUG_STREAM_GRAB("Grab thread: grabbing..."); + mGrabStatus = mZed->grab(mRunParams); // Process the full pipeline with depth + + } else { + DEBUG_GRAB("Grab thread: reading..."); + mGrabStatus = mZed->read(); // Image and sensor data reading with no depth processing + } + + DEBUG_GRAB("Grab thread: frame grabbed"); + + // ----> Grab errors? + // Note: disconnection are automatically handled by the ZED SDK + if (mGrabStatus != sl::ERROR_CODE::SUCCESS) { + if (mSvoMode && mGrabStatus == sl::ERROR_CODE::END_OF_SVOFILE_REACHED) { + // ----> Check SVO status + if (mSvoLoop) { + mSvoLoopCount++; + mZed->setSVOPosition(mSvoFrameStart); + RCLCPP_WARN_STREAM( + get_logger(), + "SVO reached the end and it has been restarted from frame #" << mSvoFrameStart); + rclcpp::sleep_for( + std::chrono::microseconds( + static_cast(mGrabPeriodMean_sec->getAvg() * 1e6))); + if (mResetPoseWithSvoLoop) { + RCLCPP_WARN( + get_logger(), + " * Camera pose reset to initial conditions."); + + mResetOdomFromSrv = true; + mOdomPath.clear(); + mPosePath.clear(); + + // Restart tracking + startPosTracking(); + } + continue; + } else { + // ----> Stop all the other threads and Timers + mThreadStop = true; + if (mPathTimer) {mPathTimer->cancel();} + if (mFusedPcTimer) {mFusedPcTimer->cancel();} + if (mTempPubTimer) {mTempPubTimer->cancel();} + if (mGnssPubCheckTimer) {mGnssPubCheckTimer->cancel();} + // <---- Stop all the other threads and Timers + + RCLCPP_WARN(get_logger(), "SVO reached the end."); + + // Force SVO status update + if (!publishSvoStatus(mFrameTimestamp.nanoseconds())) { + RCLCPP_WARN(get_logger(), "Node stopped. Press Ctrl+C to exit."); + break; + } else { + if (mPubSvoStatus) { + RCLCPP_WARN_STREAM( + get_logger(), + "Waiting for SVO status subscribers to unsubscribe. Active subscribers: " << + mPubSvoStatus->get_subscription_count()); + } + mDiagUpdater.force_update(); + rclcpp::sleep_for(1s); + continue; + } + } + // <---- Check SVO status + } else if (mGrabStatus == sl::ERROR_CODE::CAMERA_REBOOTING) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Connection issue detected: " + << sl::toString(mGrabStatus).c_str()); + rclcpp::sleep_for(1s); + continue; + } else if (mGrabStatus == sl::ERROR_CODE::CAMERA_NOT_INITIALIZED || + mGrabStatus == sl::ERROR_CODE::FAILURE) + { + RCLCPP_ERROR_STREAM( + get_logger(), + "Camera issue detected: " + << sl::toString(mGrabStatus).c_str() << ". Trying to recover the connection..."); + rclcpp::sleep_for(1s); + continue; + } else if (mGrabStatus == sl::ERROR_CODE::CORRUPTED_FRAME) { + RCLCPP_WARN_STREAM( + get_logger(), + "Grab status degraded: " + << sl::toString(mGrabStatus).c_str()); + static const int frame_grab_period = + static_cast(std::round(1000. / mCamGrabFrameRate)); + } else { + RCLCPP_ERROR_STREAM( + get_logger(), + "Critical camera error: " << sl::toString(mGrabStatus).c_str() + << ". NODE KILLED."); + mZed.reset(); + exit(EXIT_FAILURE); + } + } + // <---- Grab errors? + + mFrameCount++; + if (mSvoMode) { + mSvoFrameId = mZed->getSVOPosition(); + mSvoFrameCount = mZed->getSVONumberOfFrames(); + + // ----> Publish Clock if required + if (mUseSvoTimestamp && mPublishSvoClock) { + publishClock(mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } + // <---- Publish Clock if required + } + + if (mGnssFusionEnabled) { + // Process Fusion data + mFusionStatus = mFusion.process(); + // ----> Fusion errors? + if (mFusionStatus != sl::FUSION_ERROR_CODE::SUCCESS && + mFusionStatus != sl::FUSION_ERROR_CODE::NO_NEW_DATA_AVAILABLE) + { + RCLCPP_ERROR_STREAM( + get_logger(), + "Fusion error: " << sl::toString(mFusionStatus).c_str()); + } + // <---- Fusion errors? + } + + // ----> Timestamp + if (mSvoMode) { + if (mUseSvoTimestamp) { + mFrameTimestamp = sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } else { + mFrameTimestamp = + sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::CURRENT)); + } + } else if (mSimMode) { + if (mUseSimTime) { + mFrameTimestamp = get_clock()->now(); + } else { + mFrameTimestamp = sl_tools::slTime2Ros( + mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } + } else { + mFrameTimestamp = + sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } + //DEBUG_STREAM_COMM("Grab timestamp: " << mFrameTimestamp.nanoseconds() << " nsec"); + // <---- Timestamp + + if (mStreamingServerRequired && !mStreamingServerRunning) { + DEBUG_STR("Streaming server required, but not running"); + startStreamingServer(); + } + + if (!mSimMode) { + if (mGnssFusionEnabled && mGnssFixNew) { + mGnssFixNew = false; + + rclcpp::Time real_frame_ts = sl_tools::slTime2Ros( + mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + DEBUG_STREAM_GNSS( + "GNSS synced frame ts: " + << real_frame_ts.nanoseconds() << " nsec"); + float dT_sec = (static_cast(real_frame_ts.nanoseconds()) - + static_cast(mGnssTimestamp.nanoseconds())) / + 1e9; + DEBUG_STREAM_GNSS( + "DeltaT: " + << dT_sec << " sec [" << std::fixed << std::setprecision(9) + << static_cast(real_frame_ts.nanoseconds()) / 1e9 << "-" + << static_cast(mGnssTimestamp.nanoseconds()) / 1e9 << "]"); + + if (dT_sec < 0.0) { + RCLCPP_WARN_STREAM( + get_logger(), + "GNSS sensor and ZED Timestamps are not good. dT = " << dT_sec + << " sec"); + } + } + } + + DEBUG_STREAM_GRAB("Grab thread: publishing health status"); + publishHealthStatus(); + + // ----> Check recording status + DEBUG_STREAM_GRAB("Grab thread: checking recording status"); + mRecMutex.lock(); + if (mRecording) { + mRecStatus = mZed->getRecordingStatus(); + static int svo_rec_err_count = 0; + if (mRecStatus.is_recording && !mRecStatus.status) { + if (++svo_rec_err_count > 3) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Error saving frame to SVO"); + } + } else { + svo_rec_err_count = 0; + } + } + mRecMutex.unlock(); + // <---- Check recording status + + // ----> Retrieve Image/Depth data if someone has subscribed to + DEBUG_STREAM_GRAB("Grab thread: retrieving Image/Depth data"); + processVideoDepth(); + // <---- Retrieve Image/Depth data if someone has subscribed to + + if (!mDepthDisabled) { + // ----> Retrieve the point cloud if someone has subscribed to + DEBUG_STREAM_GRAB("Grab thread: retrieving Point Cloud data"); + processPointCloud(); + // <---- Retrieve the point cloud if someone has subscribed to + } + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use `GEN_3` even if depth is disabled + if (!mDepthDisabled || mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (!mDepthDisabled) { +#endif + // ----> Localization processing + DEBUG_STREAM_GRAB("Grab thread: Localization processing"); + if (mPosTrackingStarted) { + if (!mSvoPause) { + DEBUG_PT( + "==============================================================" + "=="); + DEBUG_PT("=== Positional Tracking status ==="); + // Update Positional Tracking status + mPosTrackingStatus = mZed->getPositionalTrackingStatus(); + + DEBUG_STREAM_PT( + " * Odometry: " + << sl::toString(mPosTrackingStatus.odometry_status).c_str() ); + DEBUG_STREAM_PT( + " * Spatial Memory: " + << sl::toString(mPosTrackingStatus.spatial_memory_status).c_str()); + DEBUG_STREAM_PT( + " * Tracking fusion: " + << sl::toString(mPosTrackingStatus.tracking_fusion_status).c_str()); + + DEBUG_PT("=== processOdometry ==="); + processOdometry(); + DEBUG_PT("=== processPose ==="); + processPose(); + if (mGnssFusionEnabled) { + if (mSvoMode) { + DEBUG_PT("=== processSvoGnssData ==="); + processSvoGnssData(); + } + DEBUG_PT("=== processGeoPose ==="); + processGeoPose(); + } + } + + // Publish `odom` and `map` TFs at the grab frequency + // RCLCPP_INFO(get_logger(), "Publishing TF -> threadFunc_zedGrab"); + DEBUG_TF("=== publishTFs ==="); + publishTFs(mFrameTimestamp); + } + // <---- Localization processing + } + + if (!mDepthDisabled) { + DEBUG_STREAM_GRAB("Grab thread: Object Detection processing"); + { + std::lock_guard lock(mObjDetMutex); + if (mObjDetRunning) { + processDetectedObjects(mFrameTimestamp); + } + } + + DEBUG_STREAM_GRAB("Grab thread: Body Tracking processing"); + { + std::lock_guard lock(mBodyTrkMutex); + if (mBodyTrkRunning) { + processBodies(mFrameTimestamp); + } + } + + DEBUG_STREAM_GRAB("Grab thread: Region of interest processing"); + // ----> Region of interest + processRtRoi(mFrameTimestamp); + // <---- Region of interest + } + + // Diagnostic statistics update + double mean_elab_sec = mElabPeriodMean_sec->addValue(grabElabTimer.toc()); + } catch (const std::exception & e) { + rcutils_reset_error(); + RCLCPP_ERROR_STREAM( + get_logger(), + "threadFunc_zedGrab: Exception: " << e.what()); + continue; + } catch (...) { + rcutils_reset_error(); + RCLCPP_ERROR( + get_logger(), + "threadFunc_zedGrab: Unknown exception."); + continue; + } + + if (mSvoMode && !mSvoRealtime) { + double effective_grab_period = mElabPeriodMean_sec->getAvg(); + mSvoExpectedPeriod = 1.0 / (mSvoRate * static_cast(mCamGrabFrameRate)); + double sleep = std::max(0.001, mSvoExpectedPeriod - effective_grab_period); + rclcpp::sleep_for(std::chrono::milliseconds(static_cast(sleep * 1000))); + + + DEBUG_STREAM_COMM( + "SVO sleep time: " << sleep << " sec - Expecter grab period:" + << mSvoExpectedPeriod << " sec - Elab time:" + << effective_grab_period << " sec"); + } + + DEBUG_STREAM_GRAB("Grab thread: iteration completed"); + } + + // Stop the heartbeat + mHeartbeatTimer->cancel(); + + DEBUG_STREAM_COMM("Grab thread finished"); +} + +bool ZedCamera::publishSensorsData(rclcpp::Time force_ts) +{ + if (mGrabStatus != sl::ERROR_CODE::SUCCESS && mGrabStatus != sl::ERROR_CODE::CORRUPTED_FRAME) { + DEBUG_SENS("Camera not ready. Sensor data not published"); + rclcpp::sleep_for(1s); + return false; + } + + // ----> Subscribers count + DEBUG_STREAM_SENS("Sensors callback: counting subscribers"); + + size_t imu_SubCount = 0; + size_t imu_RawSubCount = 0; + size_t imu_TempSubCount = 0; + size_t imu_MagSubCount = 0; + size_t pressSubCount = 0; + + try { + if (mPubImu) {imu_SubCount = count_subscribers(mPubImu->get_topic_name());} + if (mPubImuRaw) {imu_RawSubCount = count_subscribers(mPubImuRaw->get_topic_name());} + imu_MagSubCount = 0; + pressSubCount = 0; + + if (sl_tools::isZED2OrZED2i(mCamRealModel)) { + if (mPubImuMag) {imu_MagSubCount = count_subscribers(mPubImuMag->get_topic_name());} + if (mPubPressure) {pressSubCount = count_subscribers(mPubPressure->get_topic_name());} + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_SENS("pubSensorsData: Exception while counting subscribers"); + return false; + } + // <---- Subscribers count + + // ----> Grab data and setup timestamps + DEBUG_STREAM_ONCE_SENS("Sensors callback: Grab data and setup timestamps"); + rclcpp::Time ts_imu; + rclcpp::Time ts_baro; + rclcpp::Time ts_mag; + + rclcpp::Time now = get_clock()->now(); + + sl::SensorsData sens_data; + sl::ERROR_CODE err; + + if (mSensCameraSync) { + err = mZed->getSensorsData(sens_data, sl::TIME_REFERENCE::IMAGE); + } else { + err = mZed->getSensorsData(sens_data, sl::TIME_REFERENCE::CURRENT); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + // Only warn if not in SVO mode or if the error is not a benign sensor + // unavailability + if (!mSvoMode || err != sl::ERROR_CODE::SENSORS_NOT_AVAILABLE) { + RCLCPP_WARN_STREAM( + get_logger(), + "[publishSensorsData] sl::getSensorsData error: " + << sl::toString(err).c_str()); + } + return false; + } + + if (mSensCameraSync) { + ts_imu = force_ts; + ts_baro = force_ts; + ts_mag = force_ts; + } else if (mSvoMode && !mUseSvoTimestamp) { + ts_imu = now; + ts_baro = now; + ts_mag = now; + } else if (mSimMode) { + if (mUseSimTime) { + ts_imu = now; + } else { + ts_imu = sl_tools::slTime2Ros(sens_data.imu.timestamp); + } + ts_baro = ts_imu; + ts_mag = ts_imu; + } else { + ts_imu = sl_tools::slTime2Ros(sens_data.imu.timestamp); + ts_baro = sl_tools::slTime2Ros(sens_data.barometer.timestamp); + ts_mag = sl_tools::slTime2Ros(sens_data.magnetometer.timestamp); + } + // <---- Grab data and setup timestamps + + // ----> Check for duplicated data + bool new_imu_data = ts_imu != mLastTs_imu; + double dT = ts_imu.seconds() - mLastTs_imu.seconds(); + + bool new_baro_data = ts_baro != mLastTs_baro; + mLastTs_baro = ts_baro; + bool new_mag_data = ts_mag != mLastTs_mag; + mLastTs_mag = ts_mag; + + // ----> Respect data frequency for SVO2 + if (mSvoMode) { + const double imu_period = 1.0 / mSensPubRate; + + if (dT < imu_period) { + DEBUG_SENS("SENSOR: IMU data not ready yet"); + return false; + } + } + DEBUG_STREAM_SENS( + "IMU TS: " << ts_imu.seconds() << " - Grab TS: " << mFrameTimestamp.seconds() << " - Diff: " << + mFrameTimestamp.seconds() - ts_imu.seconds()); + // <---- Respect data frequency for SVO2 + + if (!new_imu_data && !new_baro_data && !new_mag_data) { + DEBUG_STREAM_SENS("No new sensors data"); + return false; + } + + if (mSimMode) { + new_baro_data = false; + new_mag_data = false; + } + // <---- Check for duplicated data + + mLastTs_imu = ts_imu; + + DEBUG_STREAM_SENS("SENSOR LAST PERIOD: " << dT << " sec @" << 1. / dT << " Hz"); + + // ----> Sensors freq for diagnostic + if (new_imu_data) { + double mean = mImuPeriodMean_sec->addValue(mImuFreqTimer.toc()); + mImuFreqTimer.tic(); + + DEBUG_STREAM_SENS("Thread New data MEAN freq: " << 1. / mean); + } + + if (new_baro_data) { + double mean = mBaroPeriodMean_sec->addValue(mBaroFreqTimer.toc()); + mBaroFreqTimer.tic(); + DEBUG_STREAM_SENS("Barometer freq: " << 1. / mean); + } + + if (new_mag_data) { + double mean = mMagPeriodMean_sec->addValue(mMagFreqTimer.toc()); + mMagFreqTimer.tic(); + + DEBUG_STREAM_SENS("Magnetometer freq: " << 1. / mean); + } + // <---- Sensors freq for diagnostic + + // ----> Sensors data publishing + if (new_imu_data) { + publishImuFrameAndTopic(); + + if (imu_SubCount > 0) { + mImuPublishing = true; + + auto imuMsg = std::make_unique(); + + imuMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : ts_imu; + imuMsg->header.frame_id = mImuFrameId; + + imuMsg->orientation.x = sens_data.imu.pose.getOrientation()[0]; + imuMsg->orientation.y = sens_data.imu.pose.getOrientation()[1]; + imuMsg->orientation.z = sens_data.imu.pose.getOrientation()[2]; + imuMsg->orientation.w = sens_data.imu.pose.getOrientation()[3]; + + imuMsg->angular_velocity.x = sens_data.imu.angular_velocity[0] * DEG2RAD; + imuMsg->angular_velocity.y = sens_data.imu.angular_velocity[1] * DEG2RAD; + imuMsg->angular_velocity.z = sens_data.imu.angular_velocity[2] * DEG2RAD; + + imuMsg->linear_acceleration.x = sens_data.imu.linear_acceleration[0]; + imuMsg->linear_acceleration.y = sens_data.imu.linear_acceleration[1]; + imuMsg->linear_acceleration.z = sens_data.imu.linear_acceleration[2]; + + // ----> Covariances copy + // Note: memcpy not allowed because ROS 2 uses double and ZED SDK uses + // float + for (int i = 0; i < 3; ++i) { + int r = 0; + + if (i == 0) { + r = 0; + } else if (i == 1) { + r = 1; + } else { + r = 2; + } + + imuMsg->orientation_covariance[i * 3 + 0] = + sens_data.imu.pose_covariance.r[r * 3 + 0] * DEG2RAD * DEG2RAD; + imuMsg->orientation_covariance[i * 3 + 1] = + sens_data.imu.pose_covariance.r[r * 3 + 1] * DEG2RAD * DEG2RAD; + imuMsg->orientation_covariance[i * 3 + 2] = + sens_data.imu.pose_covariance.r[r * 3 + 2] * DEG2RAD * DEG2RAD; + + imuMsg->linear_acceleration_covariance[i * 3 + 0] = + sens_data.imu.linear_acceleration_covariance.r[r * 3 + 0]; + imuMsg->linear_acceleration_covariance[i * 3 + 1] = + sens_data.imu.linear_acceleration_covariance.r[r * 3 + 1]; + imuMsg->linear_acceleration_covariance[i * 3 + 2] = + sens_data.imu.linear_acceleration_covariance.r[r * 3 + 2]; + + imuMsg->angular_velocity_covariance[i * 3 + 0] = + sens_data.imu.angular_velocity_covariance.r[r * 3 + 0] * DEG2RAD * + DEG2RAD; + imuMsg->angular_velocity_covariance[i * 3 + 1] = + sens_data.imu.angular_velocity_covariance.r[r * 3 + 1] * DEG2RAD * + DEG2RAD; + imuMsg->angular_velocity_covariance[i * 3 + 2] = + sens_data.imu.angular_velocity_covariance.r[r * 3 + 2] * DEG2RAD * + DEG2RAD; + } + // <---- Covariances copy + + DEBUG_STREAM_SENS("Publishing IMU message"); + try { + if (mPubImu) {mPubImu->publish(std::move(imuMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } else { + mImuPublishing = false; + } + + if (imu_RawSubCount > 0) { + mImuPublishing = true; + + auto imuRawMsg = std::make_unique(); + + imuRawMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : ts_imu; + imuRawMsg->header.frame_id = mImuFrameId; + + imuRawMsg->angular_velocity.x = + sens_data.imu.angular_velocity_uncalibrated[0] * DEG2RAD; + imuRawMsg->angular_velocity.y = + sens_data.imu.angular_velocity_uncalibrated[1] * DEG2RAD; + imuRawMsg->angular_velocity.z = + sens_data.imu.angular_velocity_uncalibrated[2] * DEG2RAD; + + imuRawMsg->linear_acceleration.x = sens_data.imu.linear_acceleration_uncalibrated[0]; + imuRawMsg->linear_acceleration.y = sens_data.imu.linear_acceleration_uncalibrated[1]; + imuRawMsg->linear_acceleration.z = sens_data.imu.linear_acceleration_uncalibrated[2]; + + // ----> Covariances copy + // Note: memcpy not allowed because ROS 2 uses double and ZED SDK uses + // float + for (int i = 0; i < 3; ++i) { + int r = 0; + + if (i == 0) { + r = 0; + } else if (i == 1) { + r = 1; + } else { + r = 2; + } + + imuRawMsg->linear_acceleration_covariance[i * 3 + 0] = + sens_data.imu.linear_acceleration_covariance.r[r * 3 + 0]; + imuRawMsg->linear_acceleration_covariance[i * 3 + 1] = + sens_data.imu.linear_acceleration_covariance.r[r * 3 + 1]; + imuRawMsg->linear_acceleration_covariance[i * 3 + 2] = + sens_data.imu.linear_acceleration_covariance.r[r * 3 + 2]; + + imuRawMsg->angular_velocity_covariance[i * 3 + 0] = + sens_data.imu.angular_velocity_covariance.r[r * 3 + 0] * DEG2RAD * + DEG2RAD; + imuRawMsg->angular_velocity_covariance[i * 3 + 1] = + sens_data.imu.angular_velocity_covariance.r[r * 3 + 1] * DEG2RAD * + DEG2RAD; + imuRawMsg->angular_velocity_covariance[i * 3 + 2] = + sens_data.imu.angular_velocity_covariance.r[r * 3 + 2] * DEG2RAD * + DEG2RAD; + } + // <---- Covariances copy + + DEBUG_STREAM_SENS("Publishing IMU RAW message"); + try { + if (mPubImuRaw) {mPubImuRaw->publish(std::move(imuRawMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + } + + if (sens_data.barometer.is_available && new_baro_data) { + if (pressSubCount > 0) { + mBaroPublishing = true; + + auto pressMsg = std::make_unique(); + + pressMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : ts_baro; + pressMsg->header.frame_id = mBaroFrameId; + pressMsg->fluid_pressure = + sens_data.barometer.pressure; // Pascals -> see + // https://github.com/ros2/common_interfaces/blob/humble/sensor_msgs/msg/FluidPressure.msg + pressMsg->variance = 1.0585e-2; + + DEBUG_STREAM_SENS("Publishing PRESS message"); + try { + if (mPubPressure) {mPubPressure->publish(std::move(pressMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } else { + mBaroPublishing = false; + } + } + + if (sens_data.magnetometer.is_available && new_mag_data) { + if (imu_MagSubCount > 0) { + mMagPublishing = true; + + auto magMsg = std::make_unique(); + + magMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : ts_mag; + magMsg->header.frame_id = mMagFrameId; + magMsg->magnetic_field.x = + sens_data.magnetometer.magnetic_field_calibrated.x * 1e-6; // Tesla + magMsg->magnetic_field.y = + sens_data.magnetometer.magnetic_field_calibrated.y * 1e-6; // Tesla + magMsg->magnetic_field.z = + sens_data.magnetometer.magnetic_field_calibrated.z * 1e-6; // Tesla + magMsg->magnetic_field_covariance[0] = 0.039e-6; + magMsg->magnetic_field_covariance[1] = 0.0f; + magMsg->magnetic_field_covariance[2] = 0.0f; + magMsg->magnetic_field_covariance[3] = 0.0f; + magMsg->magnetic_field_covariance[4] = 0.037e-6; + magMsg->magnetic_field_covariance[5] = 0.0f; + magMsg->magnetic_field_covariance[6] = 0.0f; + magMsg->magnetic_field_covariance[7] = 0.0f; + magMsg->magnetic_field_covariance[8] = 0.047e-6; + + DEBUG_STREAM_SENS("Publishing MAG message"); + try { + if (mPubImuMag) {mPubImuMag->publish(std::move(magMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } else { + mMagPublishing = false; + } + } + // <---- Sensors data publishing + + return true; +} + +void ZedCamera::publishTFs(rclcpp::Time t) +{ + // DEBUG_STREAM_TF("publishTFs"); + + // RCLCPP_INFO_STREAM(get_logger(), "publishTFs - t type:" << + // t.get_clock_type()); + + if (!mPosTrackingReady) { + return; + } + + if (t == TIMEZERO_ROS) { + DEBUG_STREAM_TF("Time zero: not publishing TFs"); + return; + } + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is + // disabled + if (!mDepthDisabled || mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (!mDepthDisabled) { +#endif + if (mPublishTF) { + publishOdomTF(t); // publish the base Frame in odometry frame + + if (mPublishMapTF) { + publishPoseTF(t); // publish the odometry Frame in map frame + } + } + } + + // Publish the camera TFs at the grab frequency, as they can be used by other nodes even if localization is not working + publishCameraTFs(t); +} + +void ZedCamera::publishCameraTFs(rclcpp::Time t) +{ + // DEBUG_STREAM_TF("publishCameraTFs"); + + if (!mZed) { + DEBUG_STREAM_TF("ZED Camera not initialized"); + return; + } + + if (!mUsingIPC && mStaticTfPublished) { + DEBUG_ONCE_TF("Static Camera TF already broadcasted"); + return; + } + + auto calib_params = mZed->getCameraInformation().camera_configuration.calibration_parameters; + const double baseline = static_cast(calib_params.getCameraBaseline()); + sl::Transform stereo_transform = calib_params.stereo_transform; + + DEBUG_STREAM_TF("Calibrated Camera baseline: " << baseline << " m"); + DEBUG_STREAM_TF( + "SDK Stereo Transform T: [" << stereo_transform.getTranslation().x << ", " + << stereo_transform.getTranslation().y << ", " + << stereo_transform.getTranslation().z << "]"); + DEBUG_STREAM_TF( + "SDK Stereo Transform R: [" + << stereo_transform.getOrientation().x << ", " + << stereo_transform.getOrientation().y << ", " + << stereo_transform.getOrientation().z << ", " + << stereo_transform.getOrientation().w << "]"); + + // ----> Validate data + bool not_valid = false; + const double EPSILON = 1e-6; + + if (std::abs(stereo_transform.getTranslation().x) > EPSILON || + std::abs(stereo_transform.getTranslation().z) > EPSILON) + { + RCLCPP_WARN_STREAM( + get_logger(), + "Unexpected calibrated stereo transform translation: [" + << stereo_transform.getTranslation().x << ", " + << stereo_transform.getTranslation().y << ", " + << stereo_transform.getTranslation().z << "]. Expected [0, " << baseline << ", 0]."); + not_valid = true; + } + if (std::abs(stereo_transform.getOrientation().x) > EPSILON || + std::abs(stereo_transform.getOrientation().y) > EPSILON || + std::abs(stereo_transform.getOrientation().z) > EPSILON || + std::abs(stereo_transform.getOrientation().w - 1.0) > EPSILON) + { + RCLCPP_WARN_STREAM( + get_logger(), + "Unexpected calibrated stereo transform rotation: [" + << stereo_transform.getOrientation().x << ", " + << stereo_transform.getOrientation().y << ", " + << stereo_transform.getOrientation().z << ", " + << stereo_transform.getOrientation().w << "]. Expected [0, 0, 0, 1]."); + not_valid = true; + } + // Note: "baseline" is a positive value, while the stereo transform y-translation is expected to be a negative value. + if (std::abs(baseline + stereo_transform.getTranslation().y) > EPSILON) { + RCLCPP_WARN_STREAM( + get_logger(), + "Baseline mismatch: Camera baseline is " << baseline << " m but calibrated stereo transform y-translation is " << + stereo_transform.getTranslation().y << " m."); + not_valid = true; + } + + if (not_valid) { + RCLCPP_WARN_STREAM( + get_logger(), "Please report this problem to Stereolabs support if you see this message, " + "adding information about your camera model and serial number: " + << sl::toString(mCamRealModel) << " - " << mCamSerialNumber); + return; + } + // <---- Validate data + + double optical_offset_x = 0.0; + + switch (mCamRealModel) { + case sl::MODEL::ZED: + optical_offset_x = -0.01; + break; + case sl::MODEL::ZED_M: + optical_offset_x = 0.0; + break; + case sl::MODEL::ZED2: + optical_offset_x = -0.01; + break; + case sl::MODEL::ZED2i: + optical_offset_x = -0.01; + break; + case sl::MODEL::ZED_X: + case sl::MODEL::ZED_XM: + case sl::MODEL::ZED_X_HDR: + case sl::MODEL::ZED_X_HDR_MAX: + case sl::MODEL::ZED_X_HDR_MINI: + optical_offset_x = -0.01; + break; + case sl::MODEL::VIRTUAL_ZED_X: + optical_offset_x = -0.01; + break; + default: + RCLCPP_ERROR_STREAM( + get_logger(), + "Unknown camera model for static TF publishing: " + << sl::toString(mCamRealModel).c_str()); + mZed.reset(); + exit(EXIT_FAILURE); + } + + // ----> Lambda function to publish transform with debug info + auto publishTransform = [&](const geometry_msgs::msg::TransformStamped & tf) { + if (mUsingIPC) { + mTfBroadcaster->sendTransform(tf); + DEBUG_STREAM_TF( + "Broadcasted new dynamic transform: " + << tf.header.frame_id << " -> " << tf.child_frame_id); + } else { + mStaticTfBroadcaster->sendTransform(tf); + DEBUG_STREAM_TF( + "Broadcasted new static transform: " + << tf.header.frame_id << " -> " << tf.child_frame_id); + } + if (_debugTf) { + double roll, pitch, yaw; + tf2::Matrix3x3( + tf2::Quaternion( + tf.transform.rotation.x, tf.transform.rotation.y, + tf.transform.rotation.z, tf.transform.rotation.w)).getRPY(roll, pitch, yaw); + DEBUG_STREAM_TF( + tf.header.stamp.sec << "." << tf.header.stamp.nanosec + << " - TF [" + << tf.header.frame_id << " -> " << tf.child_frame_id + << "] Position: (" << tf.transform.translation.x << ", " + << tf.transform.translation.y << ", " + << tf.transform.translation.z << ") - Orientation RPY: (" + << roll * RAD2DEG << ", " << pitch * RAD2DEG << ", " + << yaw * RAD2DEG << ")"); + } + }; + // <---- Lambda function to publish transform with debug info + + // ----> Common info + geometry_msgs::msg::TransformStamped transformStamped; + transformStamped.header.stamp = + mUsePubTimestamps ? get_clock()->now() : + (t + rclcpp::Duration(0, mTfOffset * 1e9)); + // <---- Common info + + // ----> New camera_center -> left_camera_frame + transformStamped.header.frame_id = mCenterFrameId; + transformStamped.child_frame_id = mLeftCamFrameId; + + transformStamped.transform.translation.x = optical_offset_x; + transformStamped.transform.translation.y = baseline / 2.0; + transformStamped.transform.translation.z = 0.0; + transformStamped.transform.rotation.x = 0.0; + transformStamped.transform.rotation.y = 0.0; + transformStamped.transform.rotation.z = 0.0; + transformStamped.transform.rotation.w = 1.0; + + // Publish transformation + publishTransform(transformStamped); + // <---- New camera_center -> left_camera_frame + + // ----> New camera_center -> right_camera_frame + transformStamped.header.frame_id = mCenterFrameId; + transformStamped.child_frame_id = mRightCamFrameId; + + transformStamped.transform.translation.x = optical_offset_x; + transformStamped.transform.translation.y = -baseline / 2.0; + transformStamped.transform.translation.z = 0.0; + transformStamped.transform.rotation.x = 0.0; + transformStamped.transform.rotation.y = 0.0; + transformStamped.transform.rotation.z = 0.0; + transformStamped.transform.rotation.w = 1.0; + + // Publish transformation + publishTransform(transformStamped); + // <---- New camera_center -> right_camera_frame + + // at the end + mStaticTfPublished = true; +} + +void ZedCamera::publishOdomTF(rclcpp::Time t) +{ + // DEBUG_STREAM_TF("publishOdomTF"); + + // ----> Avoid duplicated TF publishing + if (t == mLastTs_odom) { + return; + } + mLastTs_odom = t; + // <---- Avoid duplicated TF publishing + + if (!mSensor2BaseTransfValid) { + getSens2BaseTransform(); + } + + if (!mSensor2CameraTransfValid) { + getSens2CameraTransform(); + } + + if (!mCamera2BaseTransfValid) { + getCamera2BaseTransform(); + } + + geometry_msgs::msg::TransformStamped transformStamped; + + transformStamped.header.stamp = + mUsePubTimestamps ? get_clock()->now() : + (t + rclcpp::Duration(0, mTfOffset * 1e9)); + + // RCLCPP_INFO_STREAM(get_logger(), "Odom TS: " << + // transformStamped.header.stamp); + + transformStamped.header.frame_id = mOdomFrameId; + transformStamped.child_frame_id = mBaseFrameId; + // conversion from Tranform to message + tf2::Vector3 translation = mOdom2BaseTransf.getOrigin(); + tf2::Quaternion quat = mOdom2BaseTransf.getRotation(); + transformStamped.transform.translation.x = translation.x(); + transformStamped.transform.translation.y = translation.y(); + transformStamped.transform.translation.z = translation.z(); + transformStamped.transform.rotation.x = quat.x(); + transformStamped.transform.rotation.y = quat.y(); + transformStamped.transform.rotation.z = quat.z(); + transformStamped.transform.rotation.w = quat.w(); + + // Publish transformation + mTfBroadcaster->sendTransform(transformStamped); + + // Odom TF publishing diagnostic + double elapsed_sec = mOdomFreqTimer.toc(); + mPubOdomTF_sec->addValue(elapsed_sec); + mOdomFreqTimer.tic(); + + // Debug info + if (_debugTf) { + double roll, pitch, yaw; + tf2::Matrix3x3( + tf2::Quaternion( + transformStamped.transform.rotation.x, + transformStamped.transform.rotation.y, + transformStamped.transform.rotation.z, + transformStamped.transform.rotation.w)) + .getRPY(roll, pitch, yaw); + DEBUG_STREAM_TF( + transformStamped.header.stamp.sec << "." << transformStamped.header.stamp.nanosec + << " - TF [" << transformStamped.header.frame_id << " -> " + << transformStamped.child_frame_id << "] Position: (" + << transformStamped.transform.translation.x << ", " + << transformStamped.transform.translation.y << ", " + << transformStamped.transform.translation.z + << ") - Orientation RPY: (" << roll * RAD2DEG << ", " + << pitch * RAD2DEG << ", " << yaw * RAD2DEG << ")"); + } +} + +void ZedCamera::publishPoseTF(rclcpp::Time t) +{ + // DEBUG_STREAM_TF("publishPoseTF"); + + // ----> Avoid duplicated TF publishing + if (t == mLastTs_pose) { + return; + } + mLastTs_pose = t; + // <---- Avoid duplicated TF publishing + + if (!mSensor2BaseTransfValid) { + getSens2BaseTransform(); + } + + if (!mSensor2CameraTransfValid) { + getSens2CameraTransform(); + } + + if (!mCamera2BaseTransfValid) { + getCamera2BaseTransform(); + } + + geometry_msgs::msg::TransformStamped transformStamped; + + transformStamped.header.stamp = + mUsePubTimestamps ? get_clock()->now() : + (t + rclcpp::Duration(0, mTfOffset * 1e9)); + transformStamped.header.frame_id = mMapFrameId; + transformStamped.child_frame_id = mOdomFrameId; + // conversion from Tranform to message + tf2::Vector3 translation = mMap2OdomTransf.getOrigin(); + tf2::Quaternion quat = mMap2OdomTransf.getRotation(); + transformStamped.transform.translation.x = translation.x(); + transformStamped.transform.translation.y = translation.y(); + transformStamped.transform.translation.z = translation.z(); + transformStamped.transform.rotation.x = quat.x(); + transformStamped.transform.rotation.y = quat.y(); + transformStamped.transform.rotation.z = quat.z(); + transformStamped.transform.rotation.w = quat.w(); + + // Publish transformation + mTfBroadcaster->sendTransform(transformStamped); + + // Pose TF publishing diagnostic + double elapsed_sec = mPoseFreqTimer.toc(); + mPubPoseTF_sec->addValue(elapsed_sec); + mPoseFreqTimer.tic(); + + // Debug info + if (_debugTf) { + double roll, pitch, yaw; + tf2::Matrix3x3( + tf2::Quaternion( + transformStamped.transform.rotation.x, + transformStamped.transform.rotation.y, + transformStamped.transform.rotation.z, + transformStamped.transform.rotation.w)) + .getRPY(roll, pitch, yaw); + DEBUG_STREAM_TF( + transformStamped.header.stamp.sec << "." << transformStamped.header.stamp.nanosec + << " - TF [" << transformStamped.header.frame_id << " -> " + << transformStamped.child_frame_id << "] Position: (" + << transformStamped.transform.translation.x << ", " + << transformStamped.transform.translation.y << ", " + << transformStamped.transform.translation.z + << ") - Orientation RPY: (" << roll * RAD2DEG << ", " + << pitch * RAD2DEG << ", " << yaw * RAD2DEG << ")"); + } +} + +void ZedCamera::threadFunc_pubSensorsData() +{ + DEBUG_STREAM_SENS("Sensors thread started"); + + // Set the name of the pubSensorsData thread for easier identification in + // system monitors + pthread_setname_np(pthread_self(), (get_name() + std::string("_pubSensorsData")).c_str()); + + // ----> Advanced thread settings + if (mChangeThreadSched) { + DEBUG_STREAM_ADV("Sensors thread settings"); + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * Default Sensors thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + + if (mThreadSchedPolicy == "SCHED_OTHER") { + sched_param par; + par.sched_priority = 0; + if (pthread_setschedparam(pthread_self(), SCHED_OTHER, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_BATCH") { + sched_param par; + par.sched_priority = 0; + if (pthread_setschedparam(pthread_self(), SCHED_BATCH, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_FIFO") { + sched_param par; + par.sched_priority = mThreadPrioSens; + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_RR") { + sched_param par; + par.sched_priority = mThreadPrioSens; + if (pthread_setschedparam(pthread_self(), SCHED_RR, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else { + RCLCPP_WARN_STREAM( + get_logger(), + " ! Failed to set thread params! - Policy not supported"); + } + + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * New Sensors thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + } + // <---- Advanced thread settings + + while (1) { + try { + if (!rclcpp::ok()) { + DEBUG_STREAM_SENS("Ctrl+C received: stopping sensors thread"); + mThreadStop = true; + break; + } + if (mThreadStop) { + DEBUG_STREAM_SENS( + "threadFunc_pubSensorsData (2): Sensors thread stopped"); + break; + } + + if (mSvoMode && mSvoPause) { + if (!mGrabImuOnce) { + rclcpp::sleep_for(100ms); + continue; + } else { + mGrabImuOnce = false; // Reset the flag and grab the IMU data + } + } + + // std::lock_guard lock(mCloseZedMutex); + if (!mZed->isOpened()) { + DEBUG_STREAM_SENS( + "threadFunc_pubSensorsData: the camera is not open"); + continue; + } + + if (!publishSensorsData()) { + auto sleep_usec = + static_cast(mSensRateComp * (1000000. / mSensPubRate)); + sleep_usec = std::max(100, sleep_usec); + DEBUG_STREAM_SENS( + "[threadFunc_pubSensorsData] Thread sleep: " + << sleep_usec << " µsec"); + rclcpp::sleep_for( + std::chrono::microseconds(sleep_usec)); // Avoid busy-waiting + continue; + } + + // ----> Check publishing frequency + double sens_period_usec = 1e6 / mSensPubRate; + double avg_freq = 1. / mImuPeriodMean_sec->getAvg(); + + double err = std::fabs(mSensPubRate - avg_freq); + + const double COMP_P_GAIN = 0.0005; + + if (avg_freq < mSensPubRate) { + mSensRateComp -= COMP_P_GAIN * err; + } else if (avg_freq > mSensPubRate) { + mSensRateComp += COMP_P_GAIN * err; + } + + mSensRateComp = std::max(0.001, mSensRateComp); + mSensRateComp = std::min(3.0, mSensRateComp); + DEBUG_STREAM_SENS( + "[threadFunc_pubSensorsData] mSensRateComp: " << mSensRateComp); + // <---- Check publishing frequency + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("threadFunc_pubSensorsData: Generic exception."); + continue; + } + } + + DEBUG_STREAM_SENS("Sensors thread finished"); +} + +void ZedCamera::processOdometry() +{ + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + + if (!mSensor2BaseTransfValid) { + getSens2BaseTransform(); + } + + if (!mSensor2CameraTransfValid) { + getSens2CameraTransform(); + } + + if (!mCamera2BaseTransfValid) { + getCamera2BaseTransform(); + } + + sl::Pose deltaOdom; + linear_base = tf2::Vector3(0.0, 0.0, 0.0); + angular_base = tf2::Vector3(0.0, 0.0, 0.0); + + if (mResetOdomFromSrv || (mResetOdomWhenLoopClosure && + mPosTrackingStatus.spatial_memory_status == + sl::SPATIAL_MEMORY_STATUS::LOOP_CLOSED)) + { + + if (mPosTrackingStatus.spatial_memory_status == + sl::SPATIAL_MEMORY_STATUS::LOOP_CLOSED) + { + DEBUG_PT("=== Odometry reset for LOOP CLOSURE event ==="); + } + + // Propagate Odom transform in time + mOdom2BaseTransf.setIdentity(); + mOdomPath.clear(); + + mResetOdomFromSrv = false; + } else { + if (!mGnssFusionEnabled) { + mZed->getPosition(deltaOdom, sl::REFERENCE_FRAME::CAMERA); + } else { + mFusion.getPosition( + deltaOdom, sl::REFERENCE_FRAME::CAMERA /*,mCamUuid*/, + sl::CameraIdentifier(), sl::POSITION_TYPE::FUSION); + } + mLastZedDeltaOdom = deltaOdom; + + DEBUG_STREAM_PT( + "MAP -> Odometry Status: " + << sl::toString(mPosTrackingStatus.odometry_status).c_str()); + + DEBUG_PT( + "delta ODOM %s- [%s]:\n%s", _debugGnss ? "(`sl::Fusion`) " : "", + sl::toString(mPosTrackingStatus.odometry_status).c_str(), + deltaOdom.pose_data.getInfos().c_str()); + + if (_debugGnss) { + sl::Pose camera_delta_odom; + auto status = + mZed->getPosition(camera_delta_odom, sl::REFERENCE_FRAME::CAMERA); + + DEBUG_PT( + "delta ODOM (`sl::Camera`) [%s]:\n%s", + sl::toString(status).c_str(), + camera_delta_odom.pose_data.getInfos().c_str()); + } + + if (mPosTrackingStatus.odometry_status == sl::ODOMETRY_STATUS::OK) { + sl::Translation translation = deltaOdom.getTranslation(); + sl::Orientation quat = deltaOdom.getOrientation(); + + // Transform ZED delta odom pose in TF2 Transformation + tf2::Transform deltaOdomTf; + deltaOdomTf.setOrigin( + tf2::Vector3(translation(0), translation(1), translation(2))); + // w at the end in the constructor + deltaOdomTf.setRotation( + tf2::Quaternion(quat(0), quat(1), quat(2), quat(3))); + + // delta odom from sensor to base frame + tf2::Transform deltaOdomTf_base = + mSensor2BaseTransf.inverse() * deltaOdomTf * mSensor2BaseTransf; + + // Propagate Odom transform in time + mOdom2BaseTransf = mOdom2BaseTransf * deltaOdomTf_base; + + if (mTwoDMode) { +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51 + tf2::Vector3 tr_2d = mOdom2BaseTransf.getOrigin(); + tr_2d.setZ(mFixedZValue); + mOdom2BaseTransf.setOrigin(tr_2d); + + double roll, pitch, yaw; + tf2::Matrix3x3(mOdom2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + tf2::Quaternion quat_2d; + quat_2d.setRPY(0.0, 0.0, yaw); + + mOdom2BaseTransf.setRotation(quat_2d); +#else + if (mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { + tf2::Vector3 tr_2d = mOdom2BaseTransf.getOrigin(); + tr_2d.setZ(mFixedZValue); + mOdom2BaseTransf.setOrigin(tr_2d); + + double roll, pitch, yaw; + tf2::Matrix3x3(mOdom2BaseTransf.getRotation()) + .getRPY(roll, pitch, yaw); + + tf2::Quaternion quat_2d; + quat_2d.setRPY(0.0, 0.0, yaw); + + mOdom2BaseTransf.setRotation(quat_2d); + } else if (fabs(mFixedZValue) > 1e-6) { + tf2::Vector3 tr_2d = mOdom2BaseTransf.getOrigin(); + tr_2d.setZ(mFixedZValue); + mOdom2BaseTransf.setOrigin(tr_2d); + } +#endif + } + + // Transform twist from sensor frame to base frame + // Linear velocity: v_base = R * v_sensor + omega_sensor x r + // Angular velocity: omega_base = R * omega_sensor + tf2::Vector3 linear_sensor(deltaOdom.twist[0], deltaOdom.twist[1], deltaOdom.twist[2]); + tf2::Vector3 angular_sensor(deltaOdom.twist[3], deltaOdom.twist[4], deltaOdom.twist[5]); + + DEBUG_STREAM_PT( + "Delta ODOM Twist - Linear:" << + linear_sensor.x() << "," << linear_sensor.y() << "," << linear_sensor.z() << + " - Angular:" << angular_sensor.x() << "," << angular_sensor.y() << "," << + angular_sensor.z()); + + // Get rotation from sensor to base + tf2::Matrix3x3 rotation_sensor2base(mSensor2BaseTransf.getRotation()); + tf2::Vector3 translation_sensor2base = mSensor2BaseTransf.getOrigin(); + + // Transform angular velocity + angular_base = rotation_sensor2base * angular_sensor; + + // Transform linear velocity: v_base = R * v_sensor + omega_sensor x r + tf2::Vector3 linear_rotated = rotation_sensor2base * linear_sensor; + tf2::Vector3 cross_product = angular_base.cross(translation_sensor2base); + linear_base = linear_rotated + cross_product; + + DEBUG_STREAM_PT( + "Delta ODOM Twist - Transformed Linear:" << + linear_base.x() << "," << linear_base.y() << "," << + linear_base.z() << " - Transformed Angular:" << + angular_base.x() << "," << angular_base.y() << "," << + angular_base.z()); + + mPosTrackingReady = true; + } else if (mFloorAlignment) { + DEBUG_STREAM_THROTTLE_PT( + 5000.0, + "Odometry will be published as soon as the floor as " + "been detected for the first time"); + } + } + + if (_debugPosTracking) { + double roll, pitch, yaw; + tf2::Matrix3x3(mOdom2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + DEBUG_PT( + "+++ Odometry [%s -> %s] - {%.3f,%.3f,%.3f} {%.3f,%.3f,%.3f}", + mOdomFrameId.c_str(), mBaseFrameId.c_str(), + mOdom2BaseTransf.getOrigin().x(), mOdom2BaseTransf.getOrigin().y(), + mOdom2BaseTransf.getOrigin().z(), roll * RAD2DEG, pitch * RAD2DEG, + yaw * RAD2DEG); + } + + // Publish odometry message + publishOdom(mOdom2BaseTransf, deltaOdom, linear_base, angular_base, mFrameTimestamp); +} + +void ZedCamera::publishOdom( + tf2::Transform & odom2baseTransf, sl::Pose & slPose, const tf2::Vector3 & linear_velocity, + const tf2::Vector3 & angular_velocity, + rclcpp::Time t) +{ + size_t odomSub = 0; + + try { + odomSub = count_subscribers(mOdomTopic); // mPubOdom subscribers + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PT("publishPose: Exception while counting subscribers"); + return; + } + + if (odomSub) { + auto odomMsg = std::make_unique(); + + odomMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + odomMsg->header.frame_id = mOdomFrameId; // frame + odomMsg->child_frame_id = mBaseFrameId; // camera_frame + + // Add all value in odometry message + odomMsg->pose.pose.position.x = odom2baseTransf.getOrigin().x(); + odomMsg->pose.pose.position.y = odom2baseTransf.getOrigin().y(); + odomMsg->pose.pose.position.z = odom2baseTransf.getOrigin().z(); + odomMsg->pose.pose.orientation.x = odom2baseTransf.getRotation().x(); + odomMsg->pose.pose.orientation.y = odom2baseTransf.getRotation().y(); + odomMsg->pose.pose.orientation.z = odom2baseTransf.getRotation().z(); + odomMsg->pose.pose.orientation.w = odom2baseTransf.getRotation().w(); + + // Odometry pose covariance + for (size_t i = 0; i < odomMsg->pose.covariance.size(); i++) { + odomMsg->pose.covariance[i] = + static_cast(slPose.pose_covariance[i]); + + if (mTwoDMode) { +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51 + if (i == 14 || i == 21 || i == 28) { + odomMsg->pose.covariance[i] = 1e-9; // Very low covariance if 2D mode + } else if ((i >= 2 && i <= 4) || (i >= 8 && i <= 10) || + (i >= 12 && i <= 13) || (i >= 15 && i <= 16) || + (i >= 18 && i <= 20) || (i == 22) || (i >= 24 && i <= 27)) + { + odomMsg->pose.covariance[i] = 0.0; + } +#else + if (mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { + if (i == 14 || i == 21 || i == 28) { + odomMsg->pose.covariance[i] = 1e-9; // Very low covariance if 2D mode + } else if ((i >= 2 && i <= 4) || (i >= 8 && i <= 10) || + (i >= 12 && i <= 13) || (i >= 15 && i <= 16) || + (i >= 18 && i <= 20) || (i == 22) || (i >= 24 && i <= 27)) + { + odomMsg->pose.covariance[i] = 0.0; + } + } +#endif + } + } + + // Odometry twist + if (mTwoDMode) { + odomMsg->twist.twist.linear.x = linear_velocity.x(); + odomMsg->twist.twist.linear.y = linear_velocity.y(); + odomMsg->twist.twist.linear.z = 0.0; + odomMsg->twist.twist.angular.x = 0.0; + odomMsg->twist.twist.angular.y = 0.0; + odomMsg->twist.twist.angular.z = angular_velocity.z(); + } else { + odomMsg->twist.twist.linear.x = linear_velocity.x(); + odomMsg->twist.twist.linear.y = linear_velocity.y(); + odomMsg->twist.twist.linear.z = linear_velocity.z(); + odomMsg->twist.twist.angular.x = angular_velocity.x(); + odomMsg->twist.twist.angular.y = angular_velocity.y(); + odomMsg->twist.twist.angular.z = angular_velocity.z(); + } + + // Publish odometry message + DEBUG_STREAM_PT("Publishing ODOM message"); + try { + if (mPubOdom) {mPubOdom->publish(std::move(odomMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } +} + +void ZedCamera::processPose() +{ + if (!mSensor2BaseTransfValid) { + getSens2BaseTransform(); + } + + if (!mSensor2CameraTransfValid) { + getSens2CameraTransform(); + } + + if (!mCamera2BaseTransfValid) { + getCamera2BaseTransform(); + } + + sl::Pose pose; + sl::POSITIONAL_TRACKING_STATE pt_state; + if (!mGnssFusionEnabled && mFusionStatus != sl::FUSION_ERROR_CODE::SUCCESS) { + pt_state = mZed->getPosition(pose, sl::REFERENCE_FRAME::WORLD); + } else { + pt_state = mFusion.getPosition( + pose, sl::REFERENCE_FRAME::WORLD /*,mCamUuid*/, + sl::CameraIdentifier(), + sl::POSITION_TYPE::FUSION); + } + +#ifdef ENABLE_PT_LOCK_CHECK + // ----> Check for locked Positional Tracking + float dist = std::sqrt( + std::pow(pose.getTranslation()(0) - mLastZedPose.getTranslation()(0), 2) + + std::pow(pose.getTranslation()(1) - mLastZedPose.getTranslation()(1), 2) + + std::pow(pose.getTranslation()(2) - mLastZedPose.getTranslation()(2), 2)); + if (dist < 1e-9 && pt_state == sl::POSITIONAL_TRACKING_STATE::OK && + mPosTrackingStatus.spatial_memory_status != sl::SPATIAL_MEMORY_STATUS::LOST) + { + mPoseLocked = true; + mPoseLockCount++; + + if (mPoseLockCount > mCamGrabFrameRate) { // > 1 second + RCLCPP_WARN_STREAM( + get_logger(), + "Pos. Track. seems to be locked (pose diff.: " + << dist << " m) since " << mPoseLockCount << " frames - Status: " + << sl::toString(mPosTrackingStatus.spatial_memory_status) + .c_str()); + } + } else { + mPoseLocked = false; + mPoseLockCount = 0; + } + // <---- Check for locked Positional Tracking +#endif + + // Update last pose + mLastZedPose = pose; + + publishPoseStatus(); + publishGnssPoseStatus(); + + sl::Translation translation = mLastZedPose.getTranslation(); + sl::Orientation quat = mLastZedPose.getOrientation(); + + if (quat.sum() == 0) { + return; + } + + DEBUG_STREAM_PT( + "MAP -> Tracking Status: " + << sl::toString(mPosTrackingStatus.spatial_memory_status).c_str()); + + DEBUG_PT( + "Sensor POSE %s- [%s -> %s]:\n%s}", + _debugGnss ? "(`sl::Fusion`) " : "", mLeftCamFrameId.c_str(), + mMapFrameId.c_str(), mLastZedPose.pose_data.getInfos().c_str()); + + if (_debugGnss) { + sl::Pose camera_pose; + mZed->getPosition(camera_pose, sl::REFERENCE_FRAME::WORLD); + + DEBUG_PT( + "Sensor POSE (`sl::Camera`) [%s -> %s]:\n%s", + mLeftCamFrameId.c_str(), mMapFrameId.c_str(), + camera_pose.pose_data.getInfos().c_str()); + } + + if (mPosTrackingStatus.odometry_status == sl::ODOMETRY_STATUS::OK) { + double roll, pitch, yaw; + tf2::Matrix3x3(tf2::Quaternion(quat.ox, quat.oy, quat.oz, quat.ow)) + .getRPY(roll, pitch, yaw); + + tf2::Transform map_to_sens_transf; + map_to_sens_transf.setOrigin( + tf2::Vector3(translation(0), translation(1), translation(2))); + map_to_sens_transf.setRotation( + tf2::Quaternion(quat(0), quat(1), quat(2), quat(3))); + + mMap2BaseTransf = + map_to_sens_transf * mSensor2BaseTransf; // Base position in map frame + + if (mTwoDMode) { +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51 + tf2::Vector3 tr_2d = mMap2BaseTransf.getOrigin(); + tr_2d.setZ(mFixedZValue); + mMap2BaseTransf.setOrigin(tr_2d); + + tf2::Matrix3x3(mMap2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + tf2::Quaternion quat_2d; + quat_2d.setRPY(0.0, 0.0, yaw); + + mMap2BaseTransf.setRotation(quat_2d); +#else + if (mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { + tf2::Vector3 tr_2d = mMap2BaseTransf.getOrigin(); + tr_2d.setZ(mFixedZValue); + mMap2BaseTransf.setOrigin(tr_2d); + + tf2::Matrix3x3(mMap2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + tf2::Quaternion quat_2d; + quat_2d.setRPY(0.0, 0.0, yaw); + + mMap2BaseTransf.setRotation(quat_2d); + } else if (fabs(mFixedZValue) > 1e-6) { + tf2::Vector3 tr_2d = mMap2BaseTransf.getOrigin(); + tr_2d.setZ(mFixedZValue); + mMap2BaseTransf.setOrigin(tr_2d); + } +#endif + } + + // double roll, pitch, yaw; + tf2::Matrix3x3(mMap2BaseTransf.getRotation()).getRPY(roll, pitch, yaw); + + DEBUG_PT( + "=== Base POSE [%s -> %s] - {%.3f,%.3f,%.3f} {%.3f,%.3f,%.3f}", + mMapFrameId.c_str(), mBaseFrameId.c_str(), + mMap2BaseTransf.getOrigin().x(), mMap2BaseTransf.getOrigin().y(), + mMap2BaseTransf.getOrigin().z(), roll * RAD2DEG, pitch * RAD2DEG, + yaw * RAD2DEG); + + // Transformation from map to odometry frame + mMap2OdomTransf = mMap2BaseTransf * mOdom2BaseTransf.inverse(); + + tf2::Matrix3x3(mMap2OdomTransf.getRotation()).getRPY(roll, pitch, yaw); + + DEBUG_PT( + "+++ Diff [%s -> %s] - {%.3f,%.3f,%.3f} {%.3f,%.3f,%.3f}", + mMapFrameId.c_str(), mOdomFrameId.c_str(), + mMap2OdomTransf.getOrigin().x(), mMap2OdomTransf.getOrigin().y(), + mMap2OdomTransf.getOrigin().z(), roll * RAD2DEG, pitch * RAD2DEG, + yaw * RAD2DEG); + + + // Publish Pose message + publishPose(); + if (mPublish3DLandmarks) { + if (mFrameSkipCountLandmarks == 0) { + publishPoseLandmarks(); + mFrameSkipCountLandmarks = mPublishLandmarkSkipFrame; + } else { + mFrameSkipCountLandmarks--; + } + } + mPosTrackingReady = true; + } +} + +void ZedCamera::publishPoseStatus() +{ + size_t statusSub = 0; + + try { + statusSub = + count_subscribers(mPoseStatusTopic); // mPubPoseStatus subscribers + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PT("publishPose: Exception while counting subscribers"); + return; + } + + if (statusSub > 0) { + auto msg = std::make_unique(); + msg->odometry_status = static_cast(mPosTrackingStatus.odometry_status); + msg->spatial_memory_status = static_cast(mPosTrackingStatus.spatial_memory_status); + + try { + if (mPubPoseStatus) {mPubPoseStatus->publish(std::move(msg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } +} + +void ZedCamera::publishGnssPoseStatus() +{ + size_t statusSub = 0; + + try { + statusSub = count_subscribers( + mGnssPoseStatusTopic); // mPubGnssPoseStatus subscribers + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PT("publishPose: Exception while counting subscribers"); + return; + } + + if (statusSub > 0) { + auto msg = std::make_unique(); + + msg->gnss_fusion_status = static_cast(mFusedPosTrackingStatus.gnss_fusion_status); + + try { + if (mPubGnssPoseStatus) {mPubGnssPoseStatus->publish(std::move(msg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } +} + +void ZedCamera::publishGeoPoseStatus() +{ + size_t statusSub = 0; + + try { + statusSub = count_subscribers( + mGeoPoseStatusTopic); // mPubGnssPoseStatus subscribers + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PT("publishPose: Exception while counting subscribers"); + return; + } + + if (statusSub > 0) { + auto msg = std::make_unique(); + + msg->gnss_fusion_status = + static_cast(mFusedPosTrackingStatus.gnss_fusion_status); + + try { + if (mPubGeoPoseStatus) {mPubGeoPoseStatus->publish(std::move(msg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } +} + +void ZedCamera::publishPoseLandmarks() +{ + size_t landmarksSub = 0; + + try { + landmarksSub = + count_subscribers(mPointcloud3DLandmarksTopic); // mPubPoseLandmarks subscribers + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PT("publishPose: Exception while counting subscribers"); + return; + } + + DEBUG_STREAM_PT( + " * [publishPoseLandmarks] Subscribers to topic '" << mPointcloud3DLandmarksTopic << "': " << + landmarksSub); + + if (landmarksSub > 0) { + std::map map_lm3d; + std::vector map_lm2d; + auto res1 = mZed->getPositionalTrackingLandmarks(map_lm3d); // 3D landmarks (all the landmarks in world coords) + auto res2 = mZed->getPositionalTrackingLandmarks2D(map_lm2d); // 2D landmarks (currently tracked in image) + + if (res1 != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), + " * [publishPoseLandmarks] getPositionalTrackingLandmarks error: " << + sl::toString(res1)); + return; + } + if (res2 != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), + " * [publishPoseLandmarks] getPositionalTrackingLandmarks2D error: " << + sl::toString(res2)); + return; + } + + auto msg = std::make_unique(); + + // Initialize Point Cloud message + // https://github.com/ros/common_msgs/blob/jade-devel/sensor_msgs/include/sensor_msgs/point_cloud2_iterator.h + + int ptsCount = map_lm3d.size(); + + DEBUG_STREAM_PT(" * [publishPoseLandmarks] " << ptsCount << " landmarks to publish"); + + if (ptsCount == 0) { + DEBUG_STREAM_PT(" * [publishPoseLandmarks] No landmarks to publish, skipping..."); + return; + } + + if (mSvoMode) { + msg->header.stamp = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + } else if (mSimMode) { + if (mUseSimTime) { + msg->header.stamp = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + } else { + msg->header.stamp = mUsePubTimestamps ? get_clock()->now() : sl_tools::slTime2Ros( + mMatCloud.timestamp); + } + } else { + msg->header.stamp = mUsePubTimestamps ? get_clock()->now() : sl_tools::slTime2Ros( + mMatCloud.timestamp); + } + + msg->header.frame_id = mMapFrameId; // Set the header values of the ROS message + + int val = 1; + msg->is_bigendian = !(*reinterpret_cast(&val) == 1); + msg->is_dense = true; + + msg->width = ptsCount; + msg->height = 1; + + sensor_msgs::PointCloud2Modifier modifier(*(msg.get())); + modifier.setPointCloud2Fields( + 4, + "x", 1, sensor_msgs::msg::PointField::FLOAT32, + "y", 1, sensor_msgs::msg::PointField::FLOAT32, + "z", 1, sensor_msgs::msg::PointField::FLOAT32, + "rgb", 1, sensor_msgs::msg::PointField::FLOAT32); + + DEBUG_STREAM_PT( + " * [publishPoseLandmarks] PointCloud2 msg - Width: " << msg->width << + " - Height: " << msg->height << + " - PointStep: " << msg->point_step << + " - RowStep: " << msg->row_step << + " - Data size: " << msg->data.size()); + + sensor_msgs::PointCloud2Iterator iter_x(*msg, "x"); + sensor_msgs::PointCloud2Iterator iter_y(*msg, "y"); + sensor_msgs::PointCloud2Iterator iter_z(*msg, "z"); + sensor_msgs::PointCloud2Iterator iter_r(*msg, "r"); + sensor_msgs::PointCloud2Iterator iter_g(*msg, "g"); + sensor_msgs::PointCloud2Iterator iter_b(*msg, "b"); + sensor_msgs::PointCloud2Iterator iter_a(*msg, "a"); + + for (const auto & landmark : map_lm3d) { + // ----> Set the landmark coordinates + *iter_x = landmark.second.position.x; + *iter_y = landmark.second.position.y; + *iter_z = landmark.second.position.z; + // <---- Set the landmark coordinates + // ----> Set the landmark color (green if tracked in 2D, red if not) + // If a landmark is listed in the 2D landmarks, it means that it is currently tracked, so that we can color it in green + if (std::any_of( + map_lm2d.begin(), map_lm2d.end(), + [&landmark](const sl::Landmark2D & lm2d) {return lm2d.id == landmark.first;})) + { + *iter_r = 63; + *iter_g = 255; + *iter_b = 67; + *iter_a = 255; + } else { + *iter_r = 255; + *iter_g = 100; + *iter_b = 100; + *iter_a = 150; + } + // <---- Set the landmark color (green if tracked in 2D, red if not) + + // Increment iterators + ++iter_x; + ++iter_y; + ++iter_z; + ++iter_r; + ++iter_g; + ++iter_b; + ++iter_a; + } + + // Pointcloud publishing + DEBUG_PT(" * [publishPoseLandmarks] Publishing LANDMARK 3D POINT CLOUD message"); + +#ifdef FOUND_POINT_CLOUD_TRANSPORT + try { + mPub3DLandmarks.publish(std::move(msg)); + } catch (std::system_error & e) { + DEBUG_STREAM_PT(" * [publishPoseLandmarks] Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_PT(" * [publishPoseLandmarks] Message publishing generic exception"); + } +#else + try { + if (mPub3DLandmarks) { + mPub3DLandmarks->publish(std::move(msg)); + } else { + DEBUG_STREAM_PT(" * [publishPoseLandmarks] Publisher not initialized"); + } + } catch (std::system_error & e) { + DEBUG_STREAM_PT(" * [publishPoseLandmarks] Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_PT(" * [publishPoseLandmarks] Message publishing generic exception"); + } +#endif + } +} + +void ZedCamera::publishPose() +{ + size_t poseSub = 0; + size_t poseCovSub = 0; + + try { + poseSub = count_subscribers(mPoseTopic); // mPubPose subscribers + poseCovSub = count_subscribers(mPoseCovTopic); // mPubPoseCov subscribers + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PT("publishPose: Exception while counting subscribers"); + return; + } + + tf2::Transform base_pose; + base_pose.setIdentity(); + + base_pose = mMap2BaseTransf; + + std_msgs::msg::Header header; + header.stamp = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + header.frame_id = mMapFrameId; // frame + + geometry_msgs::msg::Pose pose; + + // Add all value in Pose message + pose.position.x = mMap2BaseTransf.getOrigin().x(); + pose.position.y = mMap2BaseTransf.getOrigin().y(); + pose.position.z = mMap2BaseTransf.getOrigin().z(); + pose.orientation.x = mMap2BaseTransf.getRotation().x(); + pose.orientation.y = mMap2BaseTransf.getRotation().y(); + pose.orientation.z = mMap2BaseTransf.getRotation().z(); + pose.orientation.w = mMap2BaseTransf.getRotation().w(); + + if (poseSub > 0) { + auto poseNoCov = std::make_unique(); + + poseNoCov->header = header; + poseNoCov->pose = pose; + + // Publish pose stamped message + DEBUG_STREAM_PT("Publishing POSE NO COV message"); + try { + if (mPubPose) {mPubPose->publish(std::move(poseNoCov));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + + if (mPublishPoseCov) { + if (poseCovSub > 0) { + auto poseCov = std::make_unique(); + + poseCov->header = header; + poseCov->pose.pose = pose; + + // Odometry pose covariance if available + + for (size_t i = 0; i < poseCov->pose.covariance.size(); i++) { + poseCov->pose.covariance[i] = + static_cast(mLastZedPose.pose_covariance[i]); + if (mTwoDMode) { +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51 + if ((i >= 2 && i <= 4) || (i >= 8 && i <= 10) || + (i >= 12 && i <= 29) || (i >= 32 && i <= 34)) + { + poseCov->pose.covariance[i] = + 1e-9; // Very low covariance if 2D mode + } +#else + if (mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { + if ((i >= 2 && i <= 4) || (i >= 8 && i <= 10) || + (i >= 12 && i <= 29) || (i >= 32 && i <= 34)) + { + poseCov->pose.covariance[i] = + 1e-9; // Very low covariance if 2D mode + } + } +#endif + } + } + + // Publish pose with covariance stamped message + DEBUG_STREAM_PT("Publishing POSE COV message"); + try { + if (mPubPoseCov) {mPubPoseCov->publish(std::move(poseCov));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + } +} + +void ZedCamera::processGeoPose() +{ + if (!mGnssMsgReceived) { + return; + } + + if (!mGnssFusionEnabled) { + return; + } + + if (!mGnss2BaseTransfValid) { + getGnss2BaseTransform(); + } + + // Update GeoPose + mFusion.getGeoPose(mLastGeoPose); + + // ----> Update GeoPose status + mFusedPosTrackingStatus = mFusion.getFusedPositionalTrackingStatus(); + publishGeoPoseStatus(); + + if (mFusedPosTrackingStatus.gnss_fusion_status != + sl::GNSS_FUSION_STATUS::OK) + { + RCLCPP_INFO_STREAM( + get_logger(), + "GNSS fusion status: " << sl::toString( + mFusedPosTrackingStatus.gnss_fusion_status)); + mGnssInitGood = false; + } + // <---- Update GeoPose status + + // ----> Setup Lat/Long + double altitude = mLastGeoPose.latlng_coordinates.getAltitude(); + if (mGnssZeroAltitude) { + altitude = 0.0; + } + mLastLatLongPose.setCoordinates( + mLastGeoPose.latlng_coordinates.getLatitude(), + mLastGeoPose.latlng_coordinates.getLongitude(), altitude, true); + + mLastHeading = mLastGeoPose.heading; + // <---- Setup Lat/Long + + // Get ECEF + sl::GeoConverter::latlng2ecef(mLastLatLongPose, mLastEcefPose); + + // Get UTM + sl::GeoConverter::latlng2utm(mLastLatLongPose, mLastUtmPose); + + DEBUG_GNSS("Good GNSS localization:"); + DEBUG_GNSS( + " * ECEF: %.6f m, %.6f m, %.6f m", mLastEcefPose.x, + mLastEcefPose.y, mLastEcefPose.z); + DEBUG_GNSS( + " * Lat. Long.: %.6f°, %.6f°,%.3f m", mLastLatLongPose.getLatitude(false), + mLastLatLongPose.getLongitude(false), mLastLatLongPose.getAltitude()); + DEBUG_GNSS(" * Heading: %.3f°", mLastHeading * RAD2DEG); + DEBUG_GNSS( + " * UTM: %.5f m, %.5f m, %.5f°, %s", mLastUtmPose.easting, + mLastUtmPose.northing, mLastUtmPose.gamma, + mLastUtmPose.UTMZone.c_str()); + + // If calibration is not good me must update the `utm -> map` transform + if (!mGnssInitGood) { + mInitEcefPose = mLastEcefPose; + mInitUtmPose = mLastUtmPose; + mInitLatLongPose = mLastLatLongPose; + mInitHeading = mLastHeading; + + if (mFusedPosTrackingStatus.gnss_fusion_status == sl::GNSS_FUSION_STATUS::OK) { + mGnssInitGood = true; + } else { + mGnssInitGood = false; + } + + RCLCPP_INFO(get_logger(), "GNSS reference localization initialized"); + + // ----> Create (static) transform UTM to MAP + // Add only Heading to pose + tf2::Quaternion pose_quat_yaw; + pose_quat_yaw.setRPY(0.0, 0.0, mLastHeading); + mLastHeadingQuat = pose_quat_yaw; + + // Set UTM transform + // Get position from ZED SDK UTM pose + mMap2UtmTransf.setOrigin( + tf2::Vector3( + mLastUtmPose.easting, mLastUtmPose.northing, + mLastGeoPose.latlng_coordinates.getAltitude())); + mMap2UtmTransf.setRotation(pose_quat_yaw); + // ----> Create (static) transform UTM to MAP + + mMap2UtmTransfValid = true; + + if (!mUtmAsParent) { + tf2::Transform map2utmInverse = mMap2UtmTransf.inverse(); + + double roll, pitch, yaw; + tf2::Matrix3x3(map2utmInverse.getRotation()).getRPY(roll, pitch, yaw); + + RCLCPP_INFO( + get_logger(), " Static transform UTM to MAP [%s -> %s]", + mUtmFrameId.c_str(), mMapFrameId.c_str()); + RCLCPP_INFO( + get_logger(), " * Translation: {%.3f,%.3f,%.3f}", + map2utmInverse.getOrigin().x(), + map2utmInverse.getOrigin().y(), + map2utmInverse.getOrigin().z()); + RCLCPP_INFO( + get_logger(), " * Rotation: {%.3f,%.3f,%.3f}", + roll * RAD2DEG, pitch * RAD2DEG, yaw * RAD2DEG); + } else { + double roll, pitch, yaw; + tf2::Matrix3x3(mMap2UtmTransf.getRotation()).getRPY(roll, pitch, yaw); + + RCLCPP_INFO( + get_logger(), " Static transform MAP to UTM [%s -> %s]", + mMapFrameId.c_str(), mUtmFrameId.c_str()); + RCLCPP_INFO( + get_logger(), " * Translation: {%.3f,%.3f,%.3f}", + mMap2UtmTransf.getOrigin().x(), + mMap2UtmTransf.getOrigin().y(), + mMap2UtmTransf.getOrigin().z()); + RCLCPP_INFO( + get_logger(), " * Rotation: {%.3f,%.3f,%.3f}", + roll * RAD2DEG, pitch * RAD2DEG, yaw * RAD2DEG); + } + } + + if (mMap2UtmTransfValid && mPublishUtmTf) { + // Publish the transform + // Note: we cannot use a static TF publisher because IPC is enabled + geometry_msgs::msg::TransformStamped transformStamped; + + transformStamped.header.stamp = + mUsePubTimestamps ? + get_clock()->now() : + (mFrameTimestamp + rclcpp::Duration(0, mTfOffset * 1e9)); + transformStamped.header.frame_id = mUtmAsParent ? mUtmFrameId : mMapFrameId; + transformStamped.child_frame_id = mUtmAsParent ? mMapFrameId : mUtmFrameId; + + // conversion from Transform to message + transformStamped.transform = mUtmAsParent ? + (tf2::toMsg(mMap2UtmTransf)) : + (tf2::toMsg(mMap2UtmTransf.inverse())); + + mTfBroadcaster->sendTransform(transformStamped); + + // Debug info + if (_debugTf) { + double roll, pitch, yaw; + tf2::Matrix3x3( + tf2::Quaternion( + transformStamped.transform.rotation.x, + transformStamped.transform.rotation.y, + transformStamped.transform.rotation.z, + transformStamped.transform.rotation.w)) + .getRPY(roll, pitch, yaw); + DEBUG_STREAM_TF( + transformStamped.header.stamp.sec << "." << transformStamped.header.stamp.nanosec + << " - TF [" + << transformStamped.header.frame_id << " -> " + << transformStamped.child_frame_id << "] Position: (" + << transformStamped.transform.translation.x << ", " + << transformStamped.transform.translation.y << ", " + << transformStamped.transform.translation.z + << ") - Orientation RPY: (" << roll * RAD2DEG << ", " + << pitch * RAD2DEG << ", " << yaw * RAD2DEG << ")"); + } + } + + publishGnssPose(); +} + +void ZedCamera::publishGnssPose() +{ + DEBUG_GNSS("=== publishGnssPose ==="); + + size_t gnssSub = 0; + size_t geoPoseSub = 0; + size_t fusedFixSub = 0; + size_t originFixSub = 0; + + try { + gnssSub = count_subscribers(mGnssPoseTopic); + geoPoseSub = count_subscribers(mGeoPoseTopic); + fusedFixSub = count_subscribers(mFusedFixTopic); + originFixSub = count_subscribers(mOriginFixTopic); + } catch (...) { + rcutils_reset_error(); + DEBUG_GNSS("publishGnssPose: Exception while counting subscribers"); + return; + } + + if (gnssSub > 0) { + auto msg = std::make_unique(); + + msg->header.stamp = + mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + msg->header.frame_id = mMapFrameId; + msg->child_frame_id = mBaseFrameId; + + // Add all value in odometry message + msg->pose.pose.position.x = mMap2BaseTransf.getOrigin().x(); + msg->pose.pose.position.y = mMap2BaseTransf.getOrigin().y(); + msg->pose.pose.position.z = mMap2BaseTransf.getOrigin().z(); + msg->pose.pose.orientation.x = mMap2BaseTransf.getRotation().x(); + msg->pose.pose.orientation.y = mMap2BaseTransf.getRotation().y(); + msg->pose.pose.orientation.z = mMap2BaseTransf.getRotation().z(); + msg->pose.pose.orientation.w = mMap2BaseTransf.getRotation().w(); + + // Odometry pose covariance + for (size_t i = 0; i < msg->pose.covariance.size(); i++) { + msg->pose.covariance[i] = + static_cast(mLastZedPose.pose_covariance[i]); + + if (mTwoDMode) { +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51 + if (i == 14 || i == 21 || i == 28) { + msg->pose.covariance[i] = 1e-9; // Very low covariance if 2D mode + } else if ((i >= 2 && i <= 4) || (i >= 8 && i <= 10) || + (i >= 12 && i <= 13) || (i >= 15 && i <= 16) || + (i >= 18 && i <= 20) || (i == 22) || (i >= 24 && i <= 27)) + { + msg->pose.covariance[i] = 0.0; + } +#else + if (mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { + if (i == 14 || i == 21 || i == 28) { + msg->pose.covariance[i] = 1e-9; // Very low covariance if 2D mode + } else if ((i >= 2 && i <= 4) || (i >= 8 && i <= 10) || + (i >= 12 && i <= 13) || (i >= 15 && i <= 16) || + (i >= 18 && i <= 20) || (i == 22) || + (i >= 24 && i <= 27)) + { + msg->pose.covariance[i] = 0.0; + } + } +#endif + } + } + + // Publish gnss message + // DEBUG_GNSS("Publishing GNSS pose message"); + try { + if (mPubGnssPose) {mPubGnssPose->publish(std::move(msg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + + if (geoPoseSub > 0) { + auto msg = std::make_unique(); + + msg->header.stamp = + mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + msg->header.frame_id = mMapFrameId; + + // Latest Lat Long data + msg->pose.position.latitude = mLastLatLongPose.getLatitude(false); + msg->pose.position.longitude = mLastLatLongPose.getLongitude(false); + msg->pose.position.altitude = mLastLatLongPose.getAltitude(); + + // Latest Heading Quaternion + msg->pose.orientation.x = mLastHeadingQuat.getX(); + msg->pose.orientation.y = mLastHeadingQuat.getY(); + msg->pose.orientation.z = mLastHeadingQuat.getZ(); + msg->pose.orientation.w = mLastHeadingQuat.getW(); + + // Publish gnss message + // DEBUG_GNSS("Publishing GeoPose message"); + try { + if (mPubGeoPose) {mPubGeoPose->publish(std::move(msg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + + if (fusedFixSub > 0) { + auto msg = std::make_unique(); + + msg->header.stamp = + mUsePubTimestamps ? get_clock()->now() : + mFrameTimestamp; + msg->header.frame_id = mMapFrameId; + + msg->status.status = sensor_msgs::msg::NavSatStatus::STATUS_SBAS_FIX; + msg->status.service = mGnssService; + msg->latitude = mLastLatLongPose.getLatitude(false); + msg->longitude = mLastLatLongPose.getLongitude(false); + msg->altitude = mLastLatLongPose.getAltitude(); + + // ----> Covariance + // Extract 3x3 position submatrix from 6x6 row-major pose covariance + // pose_covariance is [tx,ty,tz,rx,ry,rz], we need the upper-left 3x3 + msg->position_covariance_type = + sensor_msgs::msg::NavSatFix::COVARIANCE_TYPE_KNOWN; + for (size_t r = 0; r < 3; r++) { + for (size_t c = 0; c < 3; c++) { + msg->position_covariance[r * 3 + c] = + static_cast(mLastZedPose.pose_covariance[r * 6 + c]); + } + } + + if (mTwoDMode) { + bool apply2d = true; +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + if (mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { + apply2d = false; + } +#endif + if (apply2d) { + // Zero out z-related cross terms (row 2 and col 2), set cov(z,z) small + msg->position_covariance[2] = 0.0; // cov(x,z) + msg->position_covariance[5] = 0.0; // cov(y,z) + msg->position_covariance[6] = 0.0; // cov(z,x) + msg->position_covariance[7] = 0.0; // cov(z,y) + msg->position_covariance[8] = 1e-9; // cov(z,z) very low in 2D mode + } + } + // <---- Covariance + + // Publish Fused Fix message + // DEBUG_GNSS("Publishing Fused Fix message");ù + try { + if (mPubFusedFix) {mPubFusedFix->publish(std::move(msg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + + if (originFixSub > 0) { + auto msg = std::make_unique(); + + msg->header.stamp = mUsePubTimestamps ? + get_clock()->now() : + mFrameTimestamp; + msg->header.frame_id = + mGnssOriginFrameId; + + msg->status.status = sensor_msgs::msg::NavSatStatus::STATUS_SBAS_FIX; + msg->status.service = mGnssService; + msg->latitude = mInitLatLongPose.getLatitude(false); + msg->longitude = mInitLatLongPose.getLongitude(false); + msg->altitude = mInitLatLongPose.getAltitude(); + + // ----> Covariance + msg->position_covariance_type = + sensor_msgs::msg::NavSatFix::COVARIANCE_TYPE_UNKNOWN; + for (size_t i = 0; i < msg->position_covariance.size(); i++) { + msg->position_covariance[i] = -1.0; + } + // <---- Covariance + + // Publish Fused Fix message + // DEBUG_GNSS("Publishing Fused Fix message"); + try { + if (mPubOriginFix) {mPubOriginFix->publish(std::move(msg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } +} + +bool ZedCamera::isPosTrackingRequired() +{ +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is + // disabled + if (mDepthDisabled && mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (mDepthDisabled) { +#endif + DEBUG_ONCE_PT("POS. TRACKING not required: Depth disabled (unless GEN3 mode)."); + return false; + } + + if (mPosTrackingEnabled) { + DEBUG_ONCE_PT("POS. TRACKING required: enabled by param."); + return true; + } + + if (mPublishTF) { + DEBUG_ONCE_PT("POS. TRACKING required: enabled by TF param."); + + if (!mPosTrackingEnabled) { + RCLCPP_WARN_ONCE( + get_logger(), + "POSITIONAL TRACKING disabled in the parameters, but forced to " + "ENABLE because required by `pos_tracking.publish_tf: true`"); + } + return true; + } + + if (mDepthStabilization != 0) { // -1 = SDK default (> 0), so also forces tracking + DEBUG_ONCE_PT( + "POS. TRACKING required: enabled by depth stabilization param."); + +#if ((ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 52) + if (mDepthStabilization < 0) { + mDepthStabilization = 30; // Set a default value if stabilization is enabled with the SDK default setting + } +#endif + + if (!mPosTrackingEnabled) { + RCLCPP_WARN_ONCE( + get_logger(), + "POSITIONAL TRACKING disabled in the parameters, but forced to " + "ENABLE because required by `depth.depth_stabilization > 0 or -1 (SDK default)`"); + } + + return true; + } + + if (mMappingEnabled) { + DEBUG_ONCE_PT("POS. TRACKING required: enabled by mapping"); + + if (!mPosTrackingEnabled) { + RCLCPP_WARN_ONCE( + get_logger(), + "POSITIONAL TRACKING disabled in the parameters, but forced to " + "ENABLE because required by `mapping.mapping_enabled: true`"); + } + + return true; + } + + if (mObjDetEnabled && mObjDetTracking) { + DEBUG_ONCE_PT("POS. TRACKING required: enabled by object detection."); + + if (!mPosTrackingEnabled) { + RCLCPP_WARN_ONCE( + get_logger(), + "POSITIONAL TRACKING disabled in the parameters, but forced to " + "ENABLE because required by `object_detection.enable_tracking: true`"); + } + + return true; + } + + if (mBodyTrkEnabled && mBodyTrkEnableTracking) { + DEBUG_ONCE_PT("POS. TRACKING required: enabled by body tracking."); + + if (!mPosTrackingEnabled) { + RCLCPP_WARN_ONCE( + get_logger(), + "POSITIONAL TRACKING disabled in the parameters, but forced to " + "ENABLE because required by `body_tracking.enable_tracking: true`"); + } + + return true; + } + + if (!updatePosTrackingSubscribers()) { + RCLCPP_WARN( + get_logger(), + "isPosTrackingRequired: Exception while counting subscribers"); + return false; + } + + if (mPosTrackingSubCount > 0) { + DEBUG_ONCE_PT("POS. TRACKING required: topic subscribed."); + return true; + } + + if (mZed->isPositionalTrackingEnabled()) { + + DEBUG_ONCE_PT("POS. TRACKING required: enabled by ZED SDK."); + + RCLCPP_WARN_ONCE( + get_logger(), + "POSITIONAL TRACKING disabled in the parameters, enabled by the ZED SDK because required by one of the modules."); + + return true; + } + + DEBUG_ONCE_PT("POS. TRACKING not required."); + return false; +} + +bool ZedCamera::updatePosTrackingSubscribers(bool force) +{ + constexpr auto kSubQueryInterval = std::chrono::milliseconds(200); + auto now = std::chrono::steady_clock::now(); + + if (!force && mPosTrackingSubCountInit && + (now - mLastPosTrackingSubCountQuery) < kSubQueryInterval) + { + return true; + } + + mLastPosTrackingSubCountQuery = now; + mPosTrackingSubCountInit = true; + mPosTrackingSubCount = 0; + + try { + if (mPubPose) {mPosTrackingSubCount += count_subscribers(mPubPose->get_topic_name());} + if (mPubPoseCov) {mPosTrackingSubCount += count_subscribers(mPubPoseCov->get_topic_name());} + if (mPubPosePath) {mPosTrackingSubCount += count_subscribers(mPubPosePath->get_topic_name());} + if (mPubOdom) {mPosTrackingSubCount += count_subscribers(mPubOdom->get_topic_name());} + if (mPubOdomPath) {mPosTrackingSubCount += count_subscribers(mPubOdomPath->get_topic_name());} + } catch (...) { + rcutils_reset_error(); + return false; + } + + return true; +} + +void ZedCamera::callback_pubTemp() +{ + DEBUG_STREAM_ONCE_SENS("Temperatures callback called"); + + if (mGrabStatus != sl::ERROR_CODE::SUCCESS && mGrabStatus != sl::ERROR_CODE::CORRUPTED_FRAME) { + DEBUG_SENS("Camera not ready. Temperature data not published"); + rclcpp::sleep_for(1s); + return; + } + + + if (sl_tools::isZED(mCamRealModel) || sl_tools::isZEDM(mCamRealModel)) { + DEBUG_SENS( + "callback_pubTemp: the callback should never be called for the ZED " + "or " + "ZEDM camera models!"); + return; + } + + // ----> Always update temperature values for diagnostic + sl::SensorsData sens_data; + sl::ERROR_CODE err = + mZed->getSensorsData(sens_data, sl::TIME_REFERENCE::CURRENT); + if (err != sl::ERROR_CODE::SUCCESS) { + // Only warn if not in SVO mode or if the error is not a benign sensor + // unavailability + if (!mSvoMode || err != sl::ERROR_CODE::SENSORS_NOT_AVAILABLE) { + RCLCPP_WARN_STREAM( + get_logger(), + "[callback_pubTemp] sl::getSensorsData error: " + << sl::toString(err).c_str()); + } + return; + } + + if (sl_tools::isZED2OrZED2i(mCamRealModel)) { + sens_data.temperature.get( + sl::SensorsData::TemperatureData::SENSOR_LOCATION::ONBOARD_LEFT, + mTempLeft); + sens_data.temperature.get( + sl::SensorsData::TemperatureData::SENSOR_LOCATION::ONBOARD_RIGHT, + mTempRight); + } else { + mTempLeft = NOT_VALID_TEMP; + mTempRight = NOT_VALID_TEMP; + } + + sens_data.temperature.get( + sl::SensorsData::TemperatureData::SENSOR_LOCATION::IMU, mTempImu); + // <---- Always update temperature values for diagnostic + + // ----> Subscribers count + size_t tempLeftSubCount = 0; + size_t tempRightSubCount = 0; + size_t tempImuSubCount = 0; + + try { + tempLeftSubCount = 0; + tempRightSubCount = 0; + tempImuSubCount = 0; + + if (sl_tools::isZED2OrZED2i(mCamRealModel)) { + if (mPubTempL) {tempLeftSubCount = count_subscribers(mPubTempL->get_topic_name());} + if (mPubTempR) {tempRightSubCount = count_subscribers(mPubTempR->get_topic_name());} + } + if (mPubImuTemp) {tempImuSubCount = count_subscribers(mPubImuTemp->get_topic_name());} + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_SENS( + "callback_pubTemp: Exception while counting subscribers"); + return; + } + // <---- Subscribers count + + rclcpp::Time now = get_clock()->now(); + + if (tempLeftSubCount > 0) { + auto leftTempMsg = std::make_unique(); + + leftTempMsg->header.stamp = now; + + leftTempMsg->header.frame_id = mTempLeftFrameId; + leftTempMsg->temperature = static_cast(mTempLeft); + leftTempMsg->variance = 0.0; + + try { + if (mPubTempL) {mPubTempL->publish(std::move(leftTempMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + + if (tempRightSubCount > 0) { + auto rightTempMsg = std::make_unique(); + + rightTempMsg->header.stamp = now; + + rightTempMsg->header.frame_id = mTempRightFrameId; + rightTempMsg->temperature = static_cast(mTempRight); + rightTempMsg->variance = 0.0; + + DEBUG_STREAM_SENS("Publishing RIGHT TEMP message"); + try { + if (mPubTempR) {mPubTempR->publish(std::move(rightTempMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + + if (tempImuSubCount > 0) { + auto imuTempMsg = std::make_unique(); + + imuTempMsg->header.stamp = now; + + imuTempMsg->header.frame_id = mImuFrameId; + imuTempMsg->temperature = static_cast(mTempImu); + imuTempMsg->variance = 0.0; + + DEBUG_SENS("Publishing IMU TEMP message"); + try { + if (mPubImuTemp) {mPubImuTemp->publish(std::move(imuTempMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } +} + +void ZedCamera::callback_pubFusedPc() +{ + DEBUG_STREAM_ONCE_MAP("Mapping callback called"); + + auto pointcloudFusedMsg = std::make_unique(); + + uint32_t fusedCloudSubCount = 0; + try { +#ifdef FOUND_POINT_CLOUD_TRANSPORT + fusedCloudSubCount = mPubFusedCloud.getNumSubscribers(); +#else + if (mPubFusedCloud) {fusedCloudSubCount = count_subscribers(mPubFusedCloud->get_topic_name());} +#endif + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_MAP("pubFusedPc: Exception while counting subscribers"); + return; + } + + if (fusedCloudSubCount == 0) { + return; + } + + if (!mZed->isOpened()) { + return; + } + + mZed->requestSpatialMapAsync(); + + while (mZed->getSpatialMapRequestStatusAsync() == sl::ERROR_CODE::FAILURE) { + // Mesh is still generating + rclcpp::sleep_for(1ms); + } + + sl::ERROR_CODE res = mZed->retrieveSpatialMapAsync(mFusedPC); + + if (res != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Fused point cloud not extracted: " + << sl::toString(res).c_str()); + return; + } + + size_t ptsCount = mFusedPC.getNumberOfPoints(); + bool resized = false; + + if (pointcloudFusedMsg->width != ptsCount || + pointcloudFusedMsg->height != 1) + { + // Initialize Point Cloud message + // https://github.com/ros/common_msgs/blob/jade-devel/sensor_msgs/include/sensor_msgs/point_cloud2_iterator.h + pointcloudFusedMsg->header.frame_id = + mMapFrameId; // Set the header values of the ROS message + pointcloudFusedMsg->is_bigendian = false; + pointcloudFusedMsg->is_dense = false; + pointcloudFusedMsg->width = ptsCount; + pointcloudFusedMsg->height = 1; + + sensor_msgs::PointCloud2Modifier modifier(*pointcloudFusedMsg); + modifier.setPointCloud2Fields( + 4, "x", 1, sensor_msgs::msg::PointField::FLOAT32, "y", 1, + sensor_msgs::msg::PointField::FLOAT32, "z", 1, + sensor_msgs::msg::PointField::FLOAT32, "rgb", 1, + sensor_msgs::msg::PointField::FLOAT32); + + resized = true; + } + + float * ptCloudPtr = reinterpret_cast(&pointcloudFusedMsg->data[0]); + int updated = 0; + + for (size_t c = 0; c < mFusedPC.chunks.size(); c++) { + if (mFusedPC.chunks[c].has_been_updated || resized) { + updated++; + size_t chunkSize = mFusedPC.chunks[c].vertices.size(); + + if (chunkSize > 0) { + float * cloud_pts = + reinterpret_cast(mFusedPC.chunks[c].vertices.data()); + memcpy(ptCloudPtr, cloud_pts, 4 * chunkSize * sizeof(float)); + ptCloudPtr += 4 * chunkSize; + if (mSvoMode) { + pointcloudFusedMsg->header.stamp = + mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + } else if (mSimMode) { + if (mUseSimTime) { + pointcloudFusedMsg->header.stamp = + mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + } else { + pointcloudFusedMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : + sl_tools::slTime2Ros(mFusedPC.chunks[c].timestamp); + } + } else { + pointcloudFusedMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : + sl_tools::slTime2Ros(mFusedPC.chunks[c].timestamp); + } + } + } + } + + rclcpp::Time ros_ts = get_clock()->now(); + + if (mPrevTs_pc != TIMEZERO_ROS) { + mPubFusedCloudPeriodMean_sec->addValue((ros_ts - mPrevTs_pc).seconds()); + } + mPrevTs_pc = ros_ts; + + // Pointcloud publishing + DEBUG_STREAM_MAP("Publishing FUSED POINT CLOUD message"); +#ifdef FOUND_POINT_CLOUD_TRANSPORT + try { + mPubFusedCloud.publish(std::move(pointcloudFusedMsg)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } +#else + try { + if (mPubFusedCloud) {mPubFusedCloud->publish(std::move(pointcloudFusedMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } +#endif +} + +void ZedCamera::callback_pubPaths() +{ + uint32_t mapPathSub = 0; + uint32_t odomPathSub = 0; + uint32_t utmPathSub = 0; + + try { + mapPathSub = count_subscribers(mPosePathTopic); + odomPathSub = count_subscribers(mOdomPathTopic); + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PT("pubPaths: Exception while counting subscribers"); + return; + } + + geometry_msgs::msg::PoseStamped odomPose; + geometry_msgs::msg::PoseStamped mapPose; + geometry_msgs::msg::PoseStamped utmPose; + + odomPose.header.stamp = + mFrameTimestamp + rclcpp::Duration(0, mTfOffset * 1e9); + odomPose.header.frame_id = mMapFrameId; // map_frame + odomPose.pose.position.x = mOdom2BaseTransf.getOrigin().x(); + odomPose.pose.position.y = mOdom2BaseTransf.getOrigin().y(); + odomPose.pose.position.z = mOdom2BaseTransf.getOrigin().z(); + odomPose.pose.orientation.x = mOdom2BaseTransf.getRotation().x(); + odomPose.pose.orientation.y = mOdom2BaseTransf.getRotation().y(); + odomPose.pose.orientation.z = mOdom2BaseTransf.getRotation().z(); + odomPose.pose.orientation.w = mOdom2BaseTransf.getRotation().w(); + + mapPose.header.stamp = + mFrameTimestamp + rclcpp::Duration(0, mTfOffset * 1e9); + mapPose.header.frame_id = mMapFrameId; // map_frame + mapPose.pose.position.x = mMap2BaseTransf.getOrigin().x(); + mapPose.pose.position.y = mMap2BaseTransf.getOrigin().y(); + mapPose.pose.position.z = mMap2BaseTransf.getOrigin().z(); + mapPose.pose.orientation.x = mMap2BaseTransf.getRotation().x(); + mapPose.pose.orientation.y = mMap2BaseTransf.getRotation().y(); + mapPose.pose.orientation.z = mMap2BaseTransf.getRotation().z(); + mapPose.pose.orientation.w = mMap2BaseTransf.getRotation().w(); + + if (mGnssFusionEnabled) { + utmPose.header.stamp = + mFrameTimestamp + rclcpp::Duration(0, mTfOffset * 1e9); + utmPose.header.frame_id = mMapFrameId; // mUtmFrameId; // map_frame + utmPose.pose.position.x = mMap2UtmTransf.getOrigin().x(); + utmPose.pose.position.y = mMap2UtmTransf.getOrigin().y(); + utmPose.pose.position.z = mMap2UtmTransf.getOrigin().z(); + utmPose.pose.orientation.x = mMap2UtmTransf.getRotation().x(); + utmPose.pose.orientation.y = mMap2UtmTransf.getRotation().y(); + utmPose.pose.orientation.z = mMap2UtmTransf.getRotation().z(); + utmPose.pose.orientation.w = mMap2UtmTransf.getRotation().w(); + } + + // Circular vector + if (mPathMaxCount != -1) { + if (mOdomPath.size() == mPathMaxCount) { + DEBUG_STREAM_PT("Path vectors full: rotating "); + std::rotate(mOdomPath.begin(), mOdomPath.begin() + 1, mOdomPath.end()); + std::rotate(mPosePath.begin(), mPosePath.begin() + 1, mPosePath.end()); + + mPosePath[mPathMaxCount - 1] = mapPose; + mOdomPath[mPathMaxCount - 1] = odomPose; + } else { + // DEBUG_STREAM_PT( "Path vectors adding last available poses"); + mPosePath.push_back(mapPose); + mOdomPath.push_back(odomPose); + } + } else { + // DEBUG_STREAM_PT( "No limit path vectors, adding last available + // poses"); + mPosePath.push_back(mapPose); + mOdomPath.push_back(odomPose); + } + + if (mapPathSub > 0) { + auto mapPathMsg = std::make_unique(); + mapPathMsg->header.frame_id = mMapFrameId; + mapPathMsg->header.stamp = + mUsePubTimestamps ? get_clock()->now() : + mFrameTimestamp; + mapPathMsg->poses = mPosePath; + + DEBUG_STREAM_PT("Publishing MAP PATH message"); + try { + if (mPubPosePath) {mPubPosePath->publish(std::move(mapPathMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + + if (odomPathSub > 0) { + auto odomPathMsg = std::make_unique(); + odomPathMsg->header.frame_id = mOdomFrameId; + odomPathMsg->header.stamp = + mUsePubTimestamps ? get_clock()->now() : + mFrameTimestamp; + odomPathMsg->poses = mOdomPath; + + DEBUG_STREAM_PT("Publishing ODOM PATH message"); + try { + if (mPubOdomPath) {mPubOdomPath->publish(std::move(odomPathMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } +} + +void ZedCamera::callback_enableDepth( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Enable Depth service called **"); + + if (mDepthMode == sl::DEPTH_MODE::NONE) { + RCLCPP_WARN( + get_logger(), + "The node was started with depth mode NONE. Depth cannot be enabled."); + res->message = "Depth mode is NONE"; + res->success = false; + return; + } + + if (req->data) { + RCLCPP_INFO(get_logger(), "Depth processing enabled"); + mDepthDisabled = false; + res->message = "Depth processing enabled"; + } else { + RCLCPP_INFO(get_logger(), "Depth processing disabled"); + mDepthDisabled = true; + res->message = "Depth processing disabled"; + } + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is + // disabled + if (mDepthDisabled && mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3) { +#else + if (mDepthDisabled) { +#endif + RCLCPP_WARN( + get_logger(), + "Depth disabled: Positional Tracking data will not be processed."); + if (mPublishTF) { + RCLCPP_WARN( + get_logger(), + " * Unpredictable TF behavior may occur when Depth will be re-enabled."); + } + } + + if (mDepthDisabled && mObjDetEnabled) { + RCLCPP_WARN( + get_logger(), + "Depth disabled: Object Detection processing will be disabled."); + } + + if (mDepthDisabled && mBodyTrkEnabled) { + RCLCPP_WARN( + get_logger(), + "Depth disabled: Body Tracking processing will be disabled."); + } + + res->success = true; +} + +void ZedCamera::callback_saveAreaMemory( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Save Area Memory service called **"); + + if (!mPosTrackingStarted) { + RCLCPP_WARN(get_logger(), " * Pos. Tracking was not started"); + res->message = "Positional tracking not started"; + res->success = false; + return; + } + + std::string filename = req->area_file_path; + + if (filename.empty()) { + if (mAreaMemoryFilePath.empty()) { + RCLCPP_WARN( + get_logger(), + " * Empty filename and empty 'pos_tracking.area_file_path' parameter."); + res->message = "Empty filename and empty 'pos_tracking.area_file_path' parameter."; + res->success = false; + return; + } + filename = mAreaMemoryFilePath; + } + + filename = sl_tools::getFullFilePath(filename); + + if (!saveAreaMemoryFile(filename) ) { + res->message = "Error saving Area Memory File. Read node log for more information."; + res->success = false; + return; + } + + res->message = "Area Memory File saved"; + res->success = true; +} + +void ZedCamera::callback_resetOdometry( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + (void)req; + + RCLCPP_INFO(get_logger(), "** Reset Odometry service called **"); + mResetOdomFromSrv = true; + res->message = "Odometry reset OK"; + res->success = true; +} + +void ZedCamera::callback_resetPosTracking( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + (void)req; + + RCLCPP_INFO(get_logger(), "** Reset Pos. Tracking service called **"); + + if (!mPosTrackingStarted) { + RCLCPP_WARN(get_logger(), "Pos. Tracking was not started"); + res->message = "Positional tracking not active"; + res->success = false; + return; + } + + mResetOdomFromSrv = true; + mOdomPath.clear(); + mPosePath.clear(); + + // Restart tracking + startPosTracking(); + + res->message = "Positional tracking reset OK"; + res->success = true; +} + +void ZedCamera::callback_setPose( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Set Pose service called **"); + + if (mGnssFusionEnabled) { + RCLCPP_WARN( + get_logger(), + "Service call not valid: GNSS fusion is enabled."); + res->message = "GNSS fusion is enabled"; + res->success = false; + return; + } + + RCLCPP_INFO_STREAM( + get_logger(), + "New pose: [" << req->pos[0] << "," << req->pos[1] << "," + << req->pos[2] << ", " << req->orient[0] + << "," << req->orient[1] << "," + << req->orient[2] << "]"); + + if (!mPosTrackingStarted) { + RCLCPP_WARN(get_logger(), "Pos. Tracking was not active"); + res->message = "Positional tracking not active"; + res->success = false; + return; + } + + mInitialBasePose[0] = req->pos[0]; + mInitialBasePose[1] = req->pos[1]; + mInitialBasePose[2] = req->pos[2]; + + mInitialBasePose[3] = req->orient[0]; + mInitialBasePose[4] = req->orient[1]; + mInitialBasePose[5] = req->orient[2]; + + mResetOdomFromSrv = true; + mOdomPath.clear(); + mPosePath.clear(); + + // Restart tracking + startPosTracking(); + + res->message = "Positional Tracking new pose OK"; + res->success = true; +} + +void ZedCamera::callback_enableObjDet( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Enable Object Detection service called **"); + + std::lock_guard lock(mObjDetMutex); + + if (sl_tools::isZED(mCamRealModel)) { + RCLCPP_WARN(get_logger(), "Object Detection not available for ZED"); + res->message = "Object Detection not available for ZED"; + res->success = false; + return; + } + + if (req->data) { + RCLCPP_INFO(get_logger(), "Starting Object Detection"); + // Start + if (mObjDetEnabled && mObjDetRunning) { + RCLCPP_WARN(get_logger(), "Object Detection is already running"); + res->message = "Object Detection is already running"; + res->success = false; + return; + } + + mObjDetEnabled = true; + + if (startObjDetect()) { + res->message = "Object Detection started"; + res->success = true; + return; + } else { + res->message = + "Error occurred starting Object Detection. Read the log for more info"; + res->success = false; + return; + } + } else { + RCLCPP_INFO(get_logger(), "Stopping Object Detection"); + // Stop + if (!mObjDetEnabled || !mObjDetRunning) { + RCLCPP_WARN(get_logger(), "Object Detection was not running"); + res->message = "Object Detection was not running"; + res->success = false; + return; + } + + stopObjDetect(); + + res->message = "Object Detection stopped"; + res->success = true; + return; + } +} + +void ZedCamera::callback_enableBodyTrk( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Enable Body Tracking service called **"); + + std::lock_guard lock(mBodyTrkMutex); + + if (sl_tools::isZED(mCamRealModel)) { + RCLCPP_WARN(get_logger(), "Body Tracking not available for ZED"); + res->message = "Body Tracking not available for ZED"; + res->success = false; + return; + } + + if (req->data) { + RCLCPP_INFO(get_logger(), "Starting Body Tracking"); + // Start + if (mBodyTrkEnabled && mBodyTrkRunning) { + RCLCPP_WARN(get_logger(), "Body Tracking is already running"); + res->message = "Body Tracking is already running"; + res->success = false; + return; + } + + mBodyTrkEnabled = true; + + if (startBodyTracking()) { + res->message = "Body Tracking started"; + res->success = true; + return; + } else { + res->message = + "Error occurred starting Body Tracking. Read the log for more info"; + res->success = false; + return; + } + } else { + RCLCPP_INFO(get_logger(), "Stopping Body Tracking"); + // Stop + if (!mBodyTrkEnabled || !mBodyTrkRunning) { + RCLCPP_WARN(get_logger(), "Body Tracking was not running"); + res->message = "Body Tracking was not running"; + res->success = false; + return; + } + + stopBodyTracking(); + + res->message = "Body Tracking stopped"; + res->success = true; + return; + } +} + +void ZedCamera::callback_enableMapping( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Enable Spatial Mapping service called **"); + + std::lock_guard lock(mMappingMutex); + + if (req->data) { + RCLCPP_INFO(get_logger(), "Starting Spatial Mapping"); + // Start + if (mMappingEnabled && mSpatialMappingRunning) { + RCLCPP_WARN(get_logger(), "Spatial Mapping is already running"); + res->message = "Spatial Mapping is already running"; + res->success = false; + return; + } + + mMappingEnabled = true; + + if (start3dMapping()) { + res->message = "Spatial Mapping started"; + res->success = true; + return; + } else { + res->message = + "Error occurred starting Spatial Mapping. Read the log for more info"; + res->success = false; + return; + } + } else { + RCLCPP_INFO(get_logger(), "Stopping Spatial Mapping"); + // Stop + if (!mMappingEnabled || !mSpatialMappingRunning) { + mMappingEnabled = false; + mSpatialMappingRunning = false; + + RCLCPP_WARN(get_logger(), "Spatial Mapping was not running"); + res->message = "Spatial Mapping was not running"; + res->success = false; + + return; + } + + stop3dMapping(); + + res->message = "Spatial Mapping stopped"; + res->success = true; + return; + } +} + +void ZedCamera::callback_enableStreaming( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + if (req->data) { + + if (mStreamingServerRunning) { + RCLCPP_WARN(get_logger(), "A Streaming Server is already running"); + res->message = "A Streaming Server is already running"; + res->success = false; + return; + } + // Start + if (startStreamingServer()) { + res->message = "Streaming Server started"; + res->success = true; + return; + } else { + res->message = + "Error occurred starting the Streaming Server. Read the log for more info"; + res->success = false; + return; + } + } else { + // Stop + if (!mStreamingServerRunning) { + RCLCPP_WARN(get_logger(), "There is no Streaming Server active to be stopped"); + res->message = "There is no Streaming Server active to be stopped"; + res->success = false; + return; + } + + RCLCPP_INFO(get_logger(), "Stopping the Streaming Server"); + stopStreamingServer(); + + res->message = "Streaming Server stopped"; + res->success = true; + return; + } +} + +void ZedCamera::callback_startSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Start SVO Recording service called **"); + + if (mSvoMode) { + RCLCPP_WARN( + get_logger(), + "Cannot start SVO recording while playing SVO as input"); + res->message = "Cannot start SVO recording while playing SVO as input"; + res->success = false; + return; + } + + std::lock_guard lock(mRecMutex); + + if (mRecording) { + RCLCPP_WARN(get_logger(), "SVO Recording is already enabled"); + res->message = "SVO Recording is already enabled"; + res->success = false; + return; + } + + mSvoRecBitrate = req->bitrate; + if ((mSvoRecBitrate != 0) && + ((mSvoRecBitrate < 1000) || (mSvoRecBitrate > 60000))) + { + RCLCPP_WARN( + get_logger(), + "'bitrate' value not valid. Please use a value " + "in range [1000,60000], or 0 for default"); + res->message = + "'bitrate' value not valid. Please use a value in range " + "[1000,60000], or 0 for default"; + res->success = false; + return; + } + + if (req->compression_mode < 0 || req->compression_mode > 5) { + RCLCPP_WARN( + get_logger(), + "'compression_mode' mode not valid. Please use a value in " + "range [0,5]"); + res->message = + "'compression_mode' mode not valid. Please use a value in range " + "[0,5]"; + res->success = false; + return; + } + switch (req->compression_mode) { + case 1: + mSvoRecCompression = sl::SVO_COMPRESSION_MODE::H264; + break; + case 3: + mSvoRecCompression = sl::SVO_COMPRESSION_MODE::H264_LOSSLESS; + break; + case 4: + mSvoRecCompression = sl::SVO_COMPRESSION_MODE::H265_LOSSLESS; + break; + case 5: + mSvoRecCompression = sl::SVO_COMPRESSION_MODE::LOSSLESS; + break; + default: + mSvoRecCompression = sl::SVO_COMPRESSION_MODE::H265; + break; + } + mSvoRecFramerate = req->target_framerate; + mSvoRecTranscode = req->input_transcode; + mSvoRecFilename = req->svo_filename; + + if (mSvoRecFilename.empty()) { + mSvoRecFilename = "zed.svo2"; + } + + std::string err; + + if (!startSvoRecording(err)) { + res->message = "Error starting SVO recording: " + err; + res->success = false; + return; + } + + RCLCPP_INFO(get_logger(), "SVO Recording started: "); + RCLCPP_INFO_STREAM(get_logger(), " * Bitrate: " << mSvoRecBitrate); + RCLCPP_INFO_STREAM( + get_logger(), " * Compression mode: " << sl::toString( + mSvoRecCompression).c_str()); + RCLCPP_INFO_STREAM(get_logger(), " * Framerate: " << mSvoRecFramerate); + RCLCPP_INFO_STREAM( + get_logger(), + " * Input Transcode: " << (mSvoRecTranscode ? "TRUE" : "FALSE")); + RCLCPP_INFO_STREAM( + get_logger(), + " * Filename: " << (mSvoRecFilename.empty() ? "zed.svo2" : + mSvoRecFilename)); + + res->message = "SVO Recording started"; + res->success = true; +} + +void ZedCamera::callback_stopSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + (void)req; + + RCLCPP_INFO(get_logger(), "** Stop SVO Recording service called **"); + + std::lock_guard lock(mRecMutex); + + if (!mRecording) { + RCLCPP_WARN(get_logger(), "SVO Recording is NOT enabled"); + res->message = "SVO Recording is NOT enabled"; + res->success = false; + return; + } + + stopSvoRecording(); + + RCLCPP_INFO(get_logger(), "SVO Recording stopped"); + res->message = "SVO Recording stopped"; + res->success = true; +} + + +void ZedCamera::callback_pauseSvoInput( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Pause SVO Input service called **"); + + std::lock_guard lock(mRecMutex); + + if (!mSvoMode) { + RCLCPP_WARN(get_logger(), "The node is not using an SVO as input"); + res->message = "The node is not using an SVO as input"; + res->success = false; + return; + } + +#ifndef USE_SVO_REALTIME_PAUSE + if (mSvoRealtime) { + RCLCPP_WARN( + get_logger(), + "SVO input can be paused only if SVO is not in RealTime mode"); + res->message = + "SVO input can be paused only if SVO is not in RealTime mode"; + res->success = false; + mSvoPause = false; + return; + } +#endif + + if (!mSvoPause) { + RCLCPP_WARN(get_logger(), "SVO is paused"); + res->message = "SVO is paused"; + mSvoPause = true; + } else { + RCLCPP_WARN(get_logger(), "SVO is playing"); + res->message = "SVO is playing"; + mSvoPause = false; + } + res->success = true; + +#ifdef USE_SVO_REALTIME_PAUSE + mZed->pauseSVOReading(mSvoPause); +#endif + +} + +void ZedCamera::callback_setSvoFrame( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Set SVO Frame service called **"); + + constexpr double SVO_FRAME_SET_MIN_INTERVAL = + 0.5; // Minimum interval in seconds between frame changes to prevent + // excessive seeking + + // ----> Check service call frequency + if (mSetSvoFrameCheckTimer.toc() < SVO_FRAME_SET_MIN_INTERVAL) { + RCLCPP_WARN(get_logger(), "SVO frame set too fast"); + res->message = "SVO frame set too fast"; + res->success = false; + return; + } + mSetSvoFrameCheckTimer.tic(); + // <---- Check service call frequency + + std::lock_guard lock(mRecMutex); + + if (!mSvoMode) { + RCLCPP_WARN(get_logger(), "The node is not using an SVO as input"); + res->message = "The node is not using an SVO as input"; + res->success = false; + return; + } + + int frame = req->frame_id; + int svo_frames = mZed->getSVONumberOfFrames(); + if (frame >= svo_frames) { + std::stringstream ss; + ss << "Frame number is out of range. SVO has " << svo_frames << " frames"; + RCLCPP_WARN(get_logger(), ss.str().c_str()); + res->message = ss.str(); + res->success = false; + return; + } + + mZed->setSVOPosition(frame); + RCLCPP_INFO_STREAM(get_logger(), "SVO frame set to " << frame); + res->message = "SVO frame set to " + std::to_string(frame); + + if (isPosTrackingRequired()) { + // Reset odometry and paths + // ----> Set camera pose to identity + RCLCPP_WARN(get_logger(), " * Camera pose reset to identity."); + mInitialBasePose[0] = 0.0; + mInitialBasePose[1] = 0.0; + mInitialBasePose[2] = 0.0; + + mInitialBasePose[3] = 0.0; + mInitialBasePose[4] = 0.0; + mInitialBasePose[5] = 0.0; + + mResetOdomFromSrv = true; + mOdomPath.clear(); + mPosePath.clear(); + + // Restart tracking + startPosTracking(); + // <---- Set camera pose to identity + } + + //if svo is paused, ensure one grab can update topics + if (mSvoPause) { + mGrabOnce = true; + mGrabImuOnce = true; + } + + res->success = true; +} + +void ZedCamera::callback_updateDiagnostic( + diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + DEBUG_COMM("=== Update Diagnostic ==="); + + std::lock_guard lock(mCloseCameraMutex); + + if (mZed == nullptr) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::ERROR, + "Camera not opened"); + return; + } + + if (mConnStatus != sl::ERROR_CODE::SUCCESS) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::ERROR, + sl::toString(mConnStatus).c_str()); + return; + } + + if (mPoseLocked && (mPoseLockCount > mCamGrabFrameRate)) { // > 1 second + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "Positional Tracking locked. Call the service 'reset_pos_tracking' to reset."); + } + + stat.addf("Uptime", "%s", sl_tools::seconds2str(mUptimer.toc()).c_str()); + + if (mGrabStatus == sl::ERROR_CODE::SUCCESS || mGrabStatus == sl::ERROR_CODE::CORRUPTED_FRAME) { + stat.addf("IPC Enabled", "%s", mUsingIPC ? "YES" : "NO"); + + + double freq = 1. / mGrabPeriodMean_sec->getAvg(); + double freq_perc = 0.0; + if (mGrabComputeCappingFps > 0.0 && + mGrabComputeCappingFps < mCamGrabFrameRate) + { + stat.addf("Camera Grab rate -capped-", "%.1f Hz", mGrabComputeCappingFps); + freq_perc = 100. * freq / mGrabComputeCappingFps; + stat.addf( + "Data Capture -capped-", "%.1f Hz (%.1f%%)", freq, freq_perc); + } else { + stat.addf("Camera Grab rate", "%d Hz", mCamGrabFrameRate); + freq_perc = 100. * freq / mCamGrabFrameRate; + stat.addf( + "Data Capture", "Mean Frequency: %.1f Hz (%.1f%%)", freq, + freq_perc); + } + + double frame_proc_sec = mElabPeriodMean_sec->getAvg(); + double frame_grab_period = 1. / mCamGrabFrameRate; + stat.addf( + "Data Capture", "Tot. Processing Time: %.6f sec (Max. %.3f sec)", + frame_proc_sec, frame_grab_period); + + if (frame_proc_sec > frame_grab_period) { + mSysOverloadCount++; + } + + if (mSysOverloadCount >= 10) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "System overloaded. Consider reducing " + "'general.pub_frame_rate' or 'general.grab_resolution'"); + } else { + mSysOverloadCount = 0; + + if (!mPoseLocked) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::OK, + "Camera grabbing"); + } + } + + // ----> Frame drop count + auto dropped = mZed->getFrameDroppedCount(); + uint64_t total = dropped + mFrameCount; + auto perc_drop = 100. * static_cast(dropped) / total; + stat.addf( + "Frame Drop rate", "%u/%lu (%g%%)", + dropped, total, perc_drop); + // <---- Frame drop count + + if (mSimMode) { + stat.add("Input mode", "SIMULATION"); + } else if (mSvoMode) { + stat.add("Input mode", "SVO"); + } else if (mStreamMode) { + stat.add("Input mode", "LOCAL STREAM"); + } else { + stat.add("Input mode", "Live Camera"); + } + + if (mVdPublishing) { + if (mSvoMode && !mSvoRealtime) { + freq = 1. / mGrabPeriodMean_sec->getAvg(); + freq_perc = 100. * freq / mVdPubRate; + stat.addf( + "Video/Depth", "Mean Frequency: %.1f Hz (%.1f%%)", freq, + freq_perc); + } else { + freq = 1. / mVideoDepthPeriodMean_sec->getAvg(); + freq_perc = 100. * freq / mVdPubRate; + frame_grab_period = 1. / mVdPubRate; + stat.addf( + "Video/Depth", "Mean Frequency: %.1f Hz (%.1f%%)", freq, + freq_perc); + } + stat.addf( + "Video/Depth", "Processing Time: %.6f sec (Max. %.3f sec)", + mVideoDepthElabMean_sec->getAvg(), frame_grab_period); + } else { + stat.add("Video/Depth", "Topic not subscribed"); + } + + if (mSvoMode) { + double svo_perc = 100. * (static_cast(mSvoFrameId) / mSvoFrameCount); + + stat.addf( + "Playing SVO", "%sFrame: %d/%d (%.1f%%)", + (mSvoPause ? "PAUSED - " : ""), mSvoFrameId, mSvoFrameCount, svo_perc); + stat.addf("SVO Loop", "%s", (mSvoLoop ? "ON" : "OFF")); + if (mSvoLoop) { + stat.addf("SVO Loop Count", "%d", mSvoLoopCount); + } + stat.addf("SVO Real Time mode", "%s", (mSvoRealtime ? "ON" : "OFF")); + if (!mSvoRealtime) { + stat.addf("SVO Playback rate", "%.1fx -> %.1f Hz", mSvoRate, mSvoRate * mCamGrabFrameRate); + } + } + + if (!mDepthDisabled) { + stat.add("Depth status", "ACTIVE"); + stat.add("Depth mode", sl::toString(mDepthMode).c_str()); + + if (mPcPublishing) { + freq = 1. / mPcPeriodMean_sec->getAvg(); + freq_perc = 100. * freq / mPcPubRate; + stat.addf( + "Point Cloud", "Mean Frequency: %.1f Hz (%.1f%%)", freq, + freq_perc); + stat.addf( + "Point Cloud", "Processing Time: %.3f sec (Max. %.3f sec)", + mPcProcMean_sec->getAvg(), 1. / mPcPubRate); + } else { + stat.add("Point Cloud", "Topic not subscribed"); + } + + if (mFloorAlignment) { + if (mPosTrackingStatus.spatial_memory_status == sl::SPATIAL_MEMORY_STATUS::SEARCHING) { + stat.add("Floor Detection", "NOT INITIALIZED"); + } else { + stat.add("Floor Detection", "INITIALIZED"); + } + } + + if (mAutoRoiEnabled) { + stat.add("Automatic ROI", sl::toString(mAutoRoiStatus).c_str()); + } else if (mManualRoiEnabled) { + stat.add("Manual ROI", "ENABLED"); + } + + if (mObjDetRunning) { + if (mObjDetSubscribed) { + freq = 1. / mObjDetPeriodMean_sec->getAvg(); + freq_perc = 100. * freq / mVdPubRate; + frame_grab_period = 1. / mVdPubRate; + stat.addf( + "Object detection", "Mean Frequency: %.3f Hz (%.1f%%)", + freq, freq_perc); + stat.addf( + "Object detection", + "Processing Time: %.3f sec (Max. %.3f sec)", + mObjDetElabMean_sec->getAvg(), frame_grab_period); + } else { + stat.add("Object Detection", "Active, topic not subscribed"); + } + } else { + stat.add("Object Detection", "INACTIVE"); + } + + if (mBodyTrkRunning) { + if (mBodyTrkSubscribed) { + freq = 1. / mBodyTrkPeriodMean_sec->getAvg(); + freq_perc = 100. * freq / mVdPubRate; + frame_grab_period = 1. / mVdPubRate; + stat.addf( + "Body Tracking", "Mean Frequency: %.3f Hz (%.1f%%)", + freq, freq_perc); + stat.addf( + "Body Tracking", + "Processing Time: %.3f sec (Max. %.3f sec)", + mBodyTrkElabMean_sec->getAvg(), frame_grab_period); + } else { + stat.add("Body Tracking", "Active, topic not subscribed"); + } + } else { + stat.add("Body Tracking", "INACTIVE"); + } + } else { + stat.add("Depth status", "INACTIVE"); + } + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + if (!mDepthDisabled || mPosTrkMode == sl::POSITIONAL_TRACKING_MODE::GEN_3) { // With ZED SDK v5.2 we can use `GEN_3` even if depth is disabled +#else + if (!mDepthDisabled) { +#endif + stat.addf( + "Positional Tracking mode", "%s", + sl::toString(mPosTrkMode).c_str()); + + if (mPosTrackingStarted) { + stat.addf( + "Odometry status", "%s", + sl::toString(mPosTrackingStatus.odometry_status).c_str()); + stat.addf( + "Spatial Memory status", "%s", + sl::toString(mPosTrackingStatus.spatial_memory_status).c_str()); + stat.addf( + "Tracking Fusion status", "%s", + sl::toString(mPosTrackingStatus.tracking_fusion_status).c_str()); + + if (mPublishTF) { + freq = 1. / mPubOdomTF_sec->getAvg(); + stat.addf("TF Odometry", "Mean Frequency: %.1f Hz", freq); + + if (mPublishMapTF) { + freq = 1. / mPubPoseTF_sec->getAvg(); + stat.addf("TF Pose", "Mean Frequency: %.1f Hz", freq); + } else { + stat.add("TF Pose", "DISABLED"); + } + } else { + stat.add("TF Odometry", "DISABLED"); + stat.add("TF Pose", "DISABLED"); + } + + if (mMappingEnabled) { + if (mSpatialMappingRunning) { + stat.add("3D Mapping", "ACTIVE"); + } else { + stat.add("3D Mapping", "STARTING..."); + } + } else { + stat.add("3D Mapping", "INACTIVE"); + } + } else { + stat.add("Pos. Tracking status", "INACTIVE"); + } + + if (mGnssFusionEnabled) { + stat.addf("Fusion status", sl::toString(mFusionStatus).c_str()); + if (mPosTrackingStarted) { + stat.addf( + "GNSS Tracking status", "%s", + sl::toString(mFusedPosTrackingStatus.gnss_fusion_status).c_str()); + } + if (mGnssMsgReceived) { + freq = 1. / mGnssFix_sec->getAvg(); + stat.addf("GNSS input", "Mean Frequency: %.1f Hz", freq); + stat.addf("GNSS Services", "%s", mGnssServiceStr.c_str()); + if (mGnssFixValid) { + stat.add("GNSS Status", "FIX OK"); + } else { + stat.add("GNSS Status", "NO FIX"); + } + } else { + stat.add("GNSS Fusion", "Waiting for GNSS messages"); + } + } else { + stat.add("GNSS Fusion", "DISABLED"); + } + } else { + stat.add("Positional Tracking", "N/A"); + } + + if (mPublishImuTF) { + freq = 1. / mPubImuTF_sec->getAvg(); + stat.addf("TF IMU", "Mean Frequency: %.1f Hz", freq); + } else { + stat.add("TF IMU", "DISABLED"); + } + + if (mGrabStatus == sl::ERROR_CODE::CORRUPTED_FRAME) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "Performance Degraded - Corrupted frame received"); + } + } else if (mGrabStatus == sl::ERROR_CODE::LAST) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::OK, + "Camera initializing"); + } else { + stat.summaryf( + diagnostic_msgs::msg::DiagnosticStatus::ERROR, + "%s", sl::toString(mGrabStatus).c_str()); + } + + if (mImuPublishing) { + double freq = 1. / mImuPeriodMean_sec->getAvg(); + stat.addf("IMU", "Mean Frequency: %.1f Hz", freq); + } else { + stat.add("IMU Sensor", "Topics not subscribed"); + } + + if (!mSvoMode && !mSimMode && sl_tools::isZED2OrZED2i(mCamRealModel)) { + if (mMagPublishing) { + double freq = 1. / mMagPeriodMean_sec->getAvg(); + stat.addf("Magnetometer", "Mean Frequency: %.1f Hz", freq); + } else { + stat.add("Magnetometer Sensor", "Topics not subscribed"); + } + } else { + stat.add("Magnetometer Sensor", "N/A"); + } + + if (!mSvoMode && !mSimMode && sl_tools::isZED2OrZED2i(mCamRealModel)) { + if (mBaroPublishing) { + double freq = 1. / mBaroPeriodMean_sec->getAvg(); + stat.addf("Barometer", "Mean Frequency: %.1f Hz", freq); + } else { + stat.add("Barometer Sensor", "Topics not subscribed"); + } + } else { + stat.add("Barometer Sensor", "N/A"); + } + + if (!mSvoMode && !mSimMode && sl_tools::isZED2OrZED2i(mCamRealModel)) { + stat.addf("Left CMOS Temp.", "%.1f °C", mTempLeft); + stat.addf("Right CMOS Temp.", "%.1f °C", mTempRight); + + if (mTempLeft > 70.f || mTempRight > 70.f) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "High Camera temperature"); + } + } else { + stat.add("Left CMOS Temp.", "N/A"); + stat.add("Right CMOS Temp.", "N/A"); + } + + if (!mSvoMode && !mSimMode && sl_tools::isZEDX(mCamRealModel)) { + stat.addf("Camera Temp.", "%.1f °C", mTempImu); + + if (mTempImu > 70.f) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "High Camera temperature"); + } + } + + if (mRecording) { + if (!mRecStatus.status) { + // if (mGrabActive) + { + stat.add("SVO Recording", "ERROR"); + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "Error adding frames to SVO file while recording. " + "Check " + "free disk space"); + } + } else { + stat.add("SVO Recording", "ACTIVE"); + stat.addf( + "SVO compression time", "%g msec", + mRecStatus.average_compression_time); + stat.addf( + "SVO compression ratio", "%.1f%%", + mRecStatus.average_compression_ratio); + } + } else { + stat.add("SVO Recording", "NOT ACTIVE"); + } + + if (mStreamingServerRunning) { + stat.add("Streaming Server", "ACTIVE"); + + sl::StreamingParameters params; + params = mZed->getStreamingParameters(); + + stat.addf("Streaming port", "%d", static_cast(params.port)); + stat.addf( + "Streaming codec", "%s", + (params.codec == sl::STREAMING_CODEC::H264 ? "H264" : "H265")); + stat.addf("Streaming bitrate", "%d mbps", static_cast(params.bitrate)); + stat.addf("Streaming chunk size", "%d B", static_cast(params.chunk_size)); + stat.addf("Streaming GOP size", "%d", static_cast(params.gop_size)); + } else { + stat.add("Streaming Server", "NOT ACTIVE"); + } +} + +void ZedCamera::callback_gnssPubTimerTimeout() +{ + if (!mGnssMsgReceived) { + return; + } + + mGnssMsgReceived = false; + + RCLCPP_WARN( + get_logger(), + "* GNSS subscriber timeout. No GNSS data available."); + + mGnssPubCheckTimer.reset(); +} + +void ZedCamera::processSvoGnssData() +{ + if (!mGnssReplay) { + mGnssFixValid = false; + return; + } + uint64_t current_ts = mLastZedPose.timestamp.getNanoseconds(); + static uint64_t old_gnss_ts = 0; + + if (current_ts == old_gnss_ts) { + return; + } + old_gnss_ts = current_ts; + + // DEBUG_STREAM_GNSS("Retrieving GNSS data from SVO. TS: " << current_ts + // << " nsec"); + + sl::GNSSData gnssData; + auto err = mGnssReplay->grab(gnssData, current_ts); + if (err != sl::FUSION_ERROR_CODE::SUCCESS) { + //DEBUG_STREAM_GNSS("Error grabbing GNSS data from SVO: " << sl::toString(err)); + return; + } + + mGnssMsgReceived = true; + + // ----> GNSS Fix stats + double elapsed_sec = mGnssFixFreqTimer.toc(); + mGnssFix_sec->addValue(elapsed_sec); + mGnssFixFreqTimer.tic(); + // <---- GNSS Fix stats + + double latitude; + double longitude; + double altitude; + + gnssData.getCoordinates(latitude, longitude, altitude, false); + mGnssTimestamp = rclcpp::Time(gnssData.ts.getNanoseconds(), RCL_ROS_TIME); + + DEBUG_STREAM_GNSS( + "Latest GNSS data from SVO - [" + << mGnssTimestamp.nanoseconds() << " nsec] " << latitude + << "°," << longitude << "° / " << altitude << " m"); + + std::stringstream ss; + for (size_t i = 0; i < gnssData.position_covariance.size(); i++) { + ss << gnssData.position_covariance[i]; + if (i != gnssData.position_covariance.size() - 1) {ss << ", ";} + } + DEBUG_STREAM_GNSS("Covariance- [" << ss.str() << "]"); + DEBUG_STREAM_GNSS("GNSS Status: " << sl::toString(gnssData.gnss_status)); + + if (gnssData.gnss_status == sl::GNSS_STATUS::UNKNOWN) { + gnssData.gnss_status = sl::GNSS_STATUS::SINGLE; + DEBUG_STREAM_GNSS(" * Forced to: " << sl::toString(gnssData.gnss_status)); + } + + DEBUG_STREAM_GNSS("GNSS Mode: " << sl::toString(gnssData.gnss_mode)); + + mGnssFixValid = true; // Used to keep track of signal loss + + if (mZed->isOpened() && mZed->isPositionalTrackingEnabled()) { + auto ingest_error = mFusion.ingestGNSSData(gnssData); + if (ingest_error == sl::FUSION_ERROR_CODE::SUCCESS) { + DEBUG_STREAM_GNSS( + "Datum ingested - [" + << mGnssTimestamp.nanoseconds() << " nsec] " << latitude + << "°," << longitude << "° / " << altitude << " m"); + } else { + RCLCPP_ERROR_STREAM( + get_logger(), + "Ingest error occurred when ingesting GNSSData: " + << sl::toString(ingest_error)); + } + mGnssFixNew = true; + } +} + +void ZedCamera::callback_gnssFix(const sensor_msgs::msg::NavSatFix::SharedPtr msg) +{ + sl::GNSSData gnssData; + + // ----> GNSS Fix stats + double elapsed_sec = mGnssFixFreqTimer.toc(); + mGnssFix_sec->addValue(elapsed_sec); + mGnssFixFreqTimer.tic(); + // <---- GNSS Fix stats + + if (!mGnssPubCheckTimer) { + std::chrono::milliseconds gnssTimeout_msec(static_cast(2000.0)); + mGnssPubCheckTimer = create_wall_timer( + std::chrono::duration_cast( + gnssTimeout_msec), + std::bind(&ZedCamera::callback_gnssPubTimerTimeout, this)); + } else { + mGnssPubCheckTimer->reset(); + } + + mGnssMsgReceived = true; + + RCLCPP_INFO_ONCE(get_logger(), "=== GNSS subscriber ==="); + RCLCPP_INFO_ONCE( + get_logger(), + " * First message received. GNSS Sender active."); + + mGnssServiceStr = ""; + mGnssService = msg->status.service; + if (mGnssService & sensor_msgs::msg::NavSatStatus::SERVICE_GPS) { + mGnssServiceStr += "GPS "; + } + if (mGnssService & sensor_msgs::msg::NavSatStatus::SERVICE_GLONASS) { + mGnssServiceStr += "GLONASS "; + } + if (mGnssService & sensor_msgs::msg::NavSatStatus::SERVICE_COMPASS) { + mGnssServiceStr += "COMPASS "; + } + if (mGnssService & sensor_msgs::msg::NavSatStatus::SERVICE_GALILEO) { + mGnssServiceStr += "GALILEO"; + } + + RCLCPP_INFO_STREAM_ONCE( + get_logger(), + " * Service: " << mGnssServiceStr.c_str()); + + if (msg->status.status == sensor_msgs::msg::NavSatStatus::STATUS_NO_FIX) { + DEBUG_GNSS("callback_gnssFix: fix not valid"); + if (mGnssFixValid) { + RCLCPP_INFO(get_logger(), "GNSS: signal lost."); + } + mGnssFixValid = false; + + return; + } + + switch (msg->status.status) { + case ::sensor_msgs::msg::NavSatStatus::STATUS_SBAS_FIX: + gnssData.gnss_status = sl::GNSS_STATUS::RTK_FIX; + break; + case ::sensor_msgs::msg::NavSatStatus::STATUS_GBAS_FIX: + gnssData.gnss_status = sl::GNSS_STATUS::RTK_FLOAT; + break; + case ::sensor_msgs::msg::NavSatStatus::STATUS_FIX: + default: + gnssData.gnss_status = sl::GNSS_STATUS::SINGLE; + break; + } + + // ----> Check timestamp + // Note: this is the ROS timestamp, not the GNSS timestamp that is available + // in a + // "sensor_msgs/TimeReference message", e.g. `/time_reference` + uint64_t ts_gnss_part_sec = + static_cast(msg->header.stamp.sec) * 1000000000; + uint64_t ts_gnss_part_nsec = + static_cast(msg->header.stamp.nanosec); + uint64_t ts_gnss_nsec = ts_gnss_part_sec + ts_gnss_part_nsec; + + DEBUG_STREAM_GNSS( + "GNSS Ts: " << ts_gnss_part_sec / 1000000000 << " sec + " + << ts_gnss_part_nsec << " nsec = " + << ts_gnss_nsec << " nsec fused"); + + if (ts_gnss_nsec <= mLastTs_gnss_nsec) { + DEBUG_GNSS( + "callback_gnssFix: data not valid (timestamp did not increment)"); + return; + } + + DEBUG_STREAM_GNSS( + "GNSS dT: " << ts_gnss_nsec - mLastTs_gnss_nsec + << " nsec"); + mLastTs_gnss_nsec = ts_gnss_nsec; + // <---- Check timestamp + + mGnssTimestamp = rclcpp::Time(ts_gnss_nsec, RCL_ROS_TIME); + DEBUG_STREAM_GNSS("Stored Ts: " << mGnssTimestamp.nanoseconds()); + + double altit = msg->altitude; + if (mGnssZeroAltitude) { + altit = 0.0; + } + double latit = msg->latitude; + double longit = msg->longitude; + + // std::lock_guard lock(mGnssDataMutex); + gnssData.ts.setNanoseconds(ts_gnss_nsec); + gnssData.setCoordinates(latit, longit, altit, false); + + if (msg->position_covariance_type != + sensor_msgs::msg::NavSatFix::COVARIANCE_TYPE_UNKNOWN) + { + gnssData.latitude_std = msg->position_covariance[0]; + gnssData.longitude_std = msg->position_covariance[1 * 3 + 1]; + gnssData.altitude_std = msg->position_covariance[2 * 3 + 2]; + if (mGnssZeroAltitude) { + gnssData.altitude_std = 1e-9; + } + std::array position_covariance{}; + position_covariance[0] = gnssData.latitude_std * mGnssHcovMul; // X + position_covariance[1 * 3 + 1] = + gnssData.longitude_std * mGnssHcovMul; // Y + position_covariance[2 * 3 + 2] = + gnssData.altitude_std * mGnssVcovMul; // Z + gnssData.position_covariance = position_covariance; + } + + if (!mGnssFixValid) { + DEBUG_GNSS("GNSS: valid fix received."); + DEBUG_STREAM_GNSS( + " * First valid datum - Lat: " + << std::fixed << std::setprecision(9) << latit + << "° - Long: " << longit << "° - Alt: " << altit + << " m"); + } + + mGnssFixValid = true; // Used to keep track of signal loss + + if (mZed->isOpened() && mZed->isPositionalTrackingEnabled()) { + auto ingest_error = mFusion.ingestGNSSData(gnssData); + if (ingest_error == sl::FUSION_ERROR_CODE::SUCCESS) { + DEBUG_STREAM_GNSS( + "Datum ingested - [" + << mGnssTimestamp.nanoseconds() << " nsec] " << latit + << "°," << longit << "° / " << altit << " m"); + } else { + RCLCPP_ERROR_STREAM( + get_logger(), + "Ingest error occurred when ingesting GNSSData: " + << sl::toString(ingest_error)); + } + mGnssFixNew = true; + } +} + +void ZedCamera::callback_clickedPoint( + const geometry_msgs::msg::PointStamped::SharedPtr msg) +{ + // ----> Check for result subscribers + size_t markerSubCount = 0; + size_t planeSubCount = 0; + try { + if (mPubMarker) {markerSubCount = count_subscribers(mPubMarker->get_topic_name());} + if (mPubPlane) {planeSubCount = count_subscribers(mPubPlane->get_topic_name());} + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_MAP( + "callback_clickedPoint: Exception while counting point plane " + "subscribers"); + return; + } + + if ((markerSubCount + planeSubCount) == 0) { + return; + } + // <---- Check for result subscribers + + rclcpp::Time ts = get_clock()->now(); + + float X = msg->point.x; + float Y = msg->point.y; + float Z = msg->point.z; + + RCLCPP_INFO_STREAM( + get_logger(), "Clicked 3D point [X FW, Y LF, Z UP]: [" + << X << "," << Y << "," << Z << "]"); + + // ----> Transform the point from `map` frame to `left_camera_frame_optical` + double camX, camY, camZ; + try { + // Save the transformation + geometry_msgs::msg::TransformStamped m2o = + mTfBuffer->lookupTransform( + mLeftCamOptFrameId, msg->header.frame_id, + TIMEZERO_SYS, rclcpp::Duration(1, 0)); + + RCLCPP_INFO( + get_logger(), + "'%s' -> '%s': {%.3f,%.3f,%.3f} {%.3f,%.3f,%.3f,%.3f}", + msg->header.frame_id.c_str(), mLeftCamOptFrameId.c_str(), + m2o.transform.translation.x, m2o.transform.translation.y, + m2o.transform.translation.z, m2o.transform.rotation.x, + m2o.transform.rotation.y, m2o.transform.rotation.z, + m2o.transform.rotation.w); + + // Get the TF2 transformation + geometry_msgs::msg::PointStamped ptCam; + + tf2::doTransform(*(msg.get()), ptCam, m2o); + + camX = ptCam.point.x; + camY = ptCam.point.y; + camZ = ptCam.point.z; + + RCLCPP_INFO( + get_logger(), + "Point in camera coordinates [Z FW, X RG, Y DW]: {%.3f,%.3f,%.3f}", + camX, camY, camZ); + } catch (tf2::TransformException & ex) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "Transform error: %s", ex.what()); + RCLCPP_WARN_THROTTLE( + get_logger(), steady_clock, 1000.0, + "The tf from '%s' to '%s' is not available.", + msg->header.frame_id.c_str(), + mLeftCamOptFrameId.c_str()); + + return; + } + // <---- Transform the point from `map` frame to `left_camera_frame_optical` + + // ----> Project the point into 2D image coordinates + sl::CalibrationParameters zedParam; + zedParam = mZed->getCameraInformation(mMatResol) + .camera_configuration.calibration_parameters; // ok + + float f_x = zedParam.left_cam.fx; + float f_y = zedParam.left_cam.fy; + float c_x = zedParam.left_cam.cx; + float c_y = zedParam.left_cam.cy; + + float out_scale_factor = static_cast(mMatResol.width) / mCamWidth; + + float u = ((camX / camZ) * f_x + c_x) / out_scale_factor; + float v = ((camY / camZ) * f_y + c_y) / out_scale_factor; + DEBUG_STREAM_MAP( + "Clicked point image coordinates: [" + << u << "," << v + << "] - out_scale_factor: " << out_scale_factor); + // <---- Project the point into 2D image coordinates + + // ----> Extract plane from clicked point + sl::Plane plane; + sl::PlaneDetectionParameters params; + params.max_distance_threshold = mPdMaxDistanceThreshold; + params.normal_similarity_threshold = mPdNormalSimilarityThreshold; + sl::ERROR_CODE err = mZed->findPlaneAtHit(sl::uint2(u, v), plane, params); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN( + get_logger(), + "Error extracting plane at point [%.3f,%.3f,%.3f]: %s", X, Y, + Z, sl::toString(err).c_str()); + return; + } + + sl::float3 center = plane.getCenter(); + sl::float2 dims = plane.getExtents(); + + if (dims[0] == 0 || dims[1] == 0) { + RCLCPP_INFO( + get_logger(), "Plane not found at point [%.3f,%.3f,%.3f]", X, + Y, Z); + return; + } + + DEBUG_MAP( + "Found plane at point [%.3f,%.3f,%.3f] -> Center: [%.3f,%.3f,%.3f], " + "Dims: %.3fx%.3f", + X, Y, Z, center.x, center.y, center.z, dims[0], dims[1]); + // <---- Extract plane from clicked point + + if (markerSubCount > 0) { + // ----> Publish a blue sphere in the clicked point + auto pt_marker = std::make_unique(); + // Set the frame ID and timestamp. See the TF tutorials for information + // on these. + static int hit_pt_id = + 0; // This ID must be unique in the same process. Thus it is good to + // keep it as a static variable + pt_marker->header.stamp = mUsePubTimestamps ? get_clock()->now() : ts; + // Set the marker action. Options are ADD and DELETE + pt_marker->action = visualization_msgs::msg::Marker::ADD; + pt_marker->lifetime = rclcpp::Duration(0, 0); + + // Set the namespace and id for this marker. This serves to create a + // unique ID Any marker sent with the same namespace and id will overwrite + // the old one + pt_marker->ns = "plane_hit_points"; + pt_marker->id = hit_pt_id++; + pt_marker->header.frame_id = mMapFrameId; + + // Set the marker type. + pt_marker->type = visualization_msgs::msg::Marker::SPHERE; + + // Set the pose of the marker. + // This is a full 6DOF pose relative to the frame/time specified in the + // header + pt_marker->pose.position.x = X; + pt_marker->pose.position.y = Y; + pt_marker->pose.position.z = Z; + pt_marker->pose.orientation.x = 0.0; + pt_marker->pose.orientation.y = 0.0; + pt_marker->pose.orientation.z = 0.0; + pt_marker->pose.orientation.w = 1.0; + + // Set the scale of the marker -- 1x1x1 here means 1m on a side + pt_marker->scale.x = 0.025; + pt_marker->scale.y = 0.025; + pt_marker->scale.z = 0.025; + + // Set the color -- be sure to set alpha to something non-zero! + pt_marker->color.r = 0.2f; + pt_marker->color.g = 0.1f; + pt_marker->color.b = 0.75f; + pt_marker->color.a = 0.8; + + // Publish the marker + DEBUG_STREAM_MAP("Publishing PT MARKER message"); + try { + if (mPubMarker) {mPubMarker->publish(std::move(pt_marker));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + // ----> Publish a blue sphere in the clicked point + + // ----> Publish the plane as green mesh + auto plane_marker = std::make_unique(); + // Set the frame ID and timestamp. See the TF tutorials for information + // on these. + static int plane_mesh_id = + 0; // This ID must be unique in the same process. Thus it is good to + // keep it as a static variable + plane_marker->header.stamp = mUsePubTimestamps ? get_clock()->now() : ts; + // Set the marker action. Options are ADD and DELETE + plane_marker->action = visualization_msgs::msg::Marker::ADD; + plane_marker->lifetime = rclcpp::Duration(0, 0); + + // Set the namespace and id for this marker. This serves to create a + // unique ID Any marker sent with the same namespace and id will overwrite + // the old one + plane_marker->ns = "plane_meshes"; + plane_marker->id = plane_mesh_id++; + plane_marker->header.frame_id = mLeftCamFrameId; + + // Set the marker type. + plane_marker->type = visualization_msgs::msg::Marker::TRIANGLE_LIST; + + // Set the pose of the marker. This isplane_marker + plane_marker->pose.orientation.w = 1.0; + + // Set the color -- be sure to set alpha to something non-zero! + plane_marker->color.r = 0.10f; + plane_marker->color.g = 0.75f; + plane_marker->color.b = 0.20f; + plane_marker->color.a = 0.75; + + // Set the scale of the marker -- 1x1x1 here means 1m on a side + plane_marker->scale.x = 1.0; + plane_marker->scale.y = 1.0; + plane_marker->scale.z = 1.0; + + sl::Mesh mesh = plane.extractMesh(); + size_t triangCount = mesh.getNumberOfTriangles(); + size_t ptCount = triangCount * 3; + plane_marker->points.resize(ptCount); + plane_marker->colors.resize(ptCount); + + size_t ptIdx = 0; + for (size_t t = 0; t < triangCount; t++) { + for (int p = 0; p < 3; p++) { + uint vIdx = mesh.triangles[t][p]; + plane_marker->points[ptIdx].x = mesh.vertices[vIdx][0]; + plane_marker->points[ptIdx].y = mesh.vertices[vIdx][1]; + plane_marker->points[ptIdx].z = mesh.vertices[vIdx][2]; + + // Set the color -- be sure to set alpha to something non-zero! + plane_marker->colors[ptIdx].r = 0.10f; + plane_marker->colors[ptIdx].g = 0.75f; + plane_marker->colors[ptIdx].b = 0.20f; + plane_marker->colors[ptIdx].a = 0.75; + + ptIdx++; + } + } + + // Publish the marker + DEBUG_STREAM_MAP("Publishing PLANE MARKER message"); + try { + if (mPubMarker) {mPubMarker->publish(std::move(plane_marker));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + // <---- Publish the plane as green mesh + } + + if (planeSubCount > 0) { + // ----> Publish the plane as custom message + + auto planeMsg = std::make_unique(); + planeMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : ts; + planeMsg->header.frame_id = mLeftCamFrameId; + + // Plane equation + sl::float4 sl_coeff = plane.getPlaneEquation(); + planeMsg->coefficients.coef[0] = static_cast(sl_coeff[0]); + planeMsg->coefficients.coef[1] = static_cast(sl_coeff[1]); + planeMsg->coefficients.coef[2] = static_cast(sl_coeff[2]); + planeMsg->coefficients.coef[3] = static_cast(sl_coeff[3]); + + // Plane Normal + sl::float3 sl_normal = plane.getNormal(); + planeMsg->normal.x = sl_normal[0]; + planeMsg->normal.y = sl_normal[1]; + planeMsg->normal.z = sl_normal[2]; + + // Plane Center + sl::float3 sl_center = plane.getCenter(); + planeMsg->center.x = sl_center[0]; + planeMsg->center.y = sl_center[1]; + planeMsg->center.z = sl_center[2]; + + // Plane extents + sl::float3 sl_extents = plane.getExtents(); + planeMsg->extents[0] = sl_extents[0]; + planeMsg->extents[1] = sl_extents[1]; + + // Plane pose + sl::Pose sl_pose = plane.getPose(); + sl::Orientation sl_rot = sl_pose.getOrientation(); + sl::Translation sl_tr = sl_pose.getTranslation(); + + planeMsg->pose.rotation.x = sl_rot.ox; + planeMsg->pose.rotation.y = sl_rot.oy; + planeMsg->pose.rotation.z = sl_rot.oz; + planeMsg->pose.rotation.w = sl_rot.ow; + + planeMsg->pose.translation.x = sl_tr.x; + planeMsg->pose.translation.y = sl_tr.y; + planeMsg->pose.translation.z = sl_tr.z; + + // Plane Bounds + std::vector sl_bounds = plane.getBounds(); + planeMsg->bounds.points.resize(sl_bounds.size()); + memcpy( + planeMsg->bounds.points.data(), sl_bounds.data(), + 3 * sl_bounds.size() * sizeof(float)); + + // Plane mesh + sl::Mesh sl_mesh = plane.extractMesh(); + size_t triangCount = sl_mesh.triangles.size(); + size_t ptsCount = sl_mesh.vertices.size(); + planeMsg->mesh.triangles.resize(triangCount); + planeMsg->mesh.vertices.resize(ptsCount); + + // memcpy not allowed because data types are different + for (size_t i = 0; i < triangCount; i++) { + planeMsg->mesh.triangles[i].vertex_indices[0] = sl_mesh.triangles[i][0]; + planeMsg->mesh.triangles[i].vertex_indices[1] = sl_mesh.triangles[i][1]; + planeMsg->mesh.triangles[i].vertex_indices[2] = sl_mesh.triangles[i][2]; + } + + // memcpy not allowed because data types are different + for (size_t i = 0; i < ptsCount; i++) { + planeMsg->mesh.vertices[i].x = sl_mesh.vertices[i][0]; + planeMsg->mesh.vertices[i].y = sl_mesh.vertices[i][1]; + planeMsg->mesh.vertices[i].z = sl_mesh.vertices[i][2]; + } + + DEBUG_STREAM_MAP("Publishing PLANE message"); + try { + if (mPubPlane) {mPubPlane->publish(std::move(planeMsg));} + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + // <---- Publish the plane as custom message + } +} + +void ZedCamera::callback_setRoi( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Set ROI service called **"); + + if (mDepthDisabled) { + std::string err_msg = + "Error while setting ZED SDK region of interest: depth processing is " + "disabled!"; + + RCLCPP_WARN_STREAM(get_logger(), " * " << err_msg); + + res->message = err_msg; + res->success = false; + return; + } + + RCLCPP_INFO_STREAM(get_logger(), " * ROI string: " << req->roi.c_str()); + + if (req->roi == "") { + std::string err_msg = + "Error while setting ZED SDK region of interest: a vector of " + "normalized points describing a " + "polygon is required. e.g. " + "'[[0.5,0.25],[0.75,0.5],[0.5,0.75],[0.25,0.5]]'"; + + RCLCPP_WARN_STREAM(get_logger(), " * " << err_msg); + + res->message = err_msg; + res->success = false; + return; + } + + std::string error; + std::vector> parsed_poly = + sl_tools::parseStringMultiVector_float(req->roi, error); + + if (error != "") { + std::string err_msg = "Error while setting ZED SDK region of interest: "; + err_msg += error; + + RCLCPP_WARN_STREAM(get_logger(), " * " << err_msg); + + res->message = err_msg; + res->success = false; + return; + } + + // ----> Set Region of Interest + // Create mask + RCLCPP_INFO(get_logger(), " * Setting ROI"); + std::vector sl_poly; + parseRoiPoly(parsed_poly, sl_poly); + + sl::Resolution resol(mCamWidth, mCamHeight); + sl::Mat roi_mask(resol, sl::MAT_TYPE::U8_C1, sl::MEM::CPU); + if (!sl_tools::generateROI(sl_poly, roi_mask)) { + std::string err_msg = + "Error generating the region of interest image mask. "; + err_msg += error; + + RCLCPP_WARN_STREAM(get_logger(), " * " << err_msg); + + res->message = err_msg; + res->success = false; + return; + } else { + sl::ERROR_CODE err = mZed->setRegionOfInterest(roi_mask); + if (err != sl::ERROR_CODE::SUCCESS) { + std::string err_msg = + "Error while setting ZED SDK region of interest: "; + err_msg += sl::toString(err).c_str(); + + RCLCPP_WARN_STREAM(get_logger(), " * " << err_msg); + + mManualRoiEnabled = false; + + + if (_nitrosDisabled) { + if (mPubRoiMask.getTopic().empty()) { + mPubRoiMask = image_transport::create_publisher( + this, mRoiMaskTopic, mQos.get_rmw_qos_profile()); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mPubRoiMask.getTopic()); + } + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + if (!mNitrosPubRoiMask) { + mNitrosPubRoiMask = std::make_shared< + nvidia::isaac_ros::nitros::ManagedNitrosPublisher< + nvidia::isaac_ros::nitros::NitrosImage>>( + this, mRoiMaskTopic, + nvidia::isaac_ros::nitros::nitros_image_bgra8_t:: + supported_type_name, + nvidia::isaac_ros::nitros::NitrosDiagnosticsConfig(), mQos); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mRoiMaskTopic); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << mRoiMaskTopic + "/nitros"); + } +#endif + } + + res->message = err_msg; + res->success = false; + return; + } else { + RCLCPP_INFO(get_logger(), " * Region of Interest correctly set."); + + mManualRoiEnabled = true; + + res->message = "Region of Interest correctly set."; + res->success = true; + return; + } + } + // <---- Set Region of Interest +} + +void ZedCamera::callback_resetRoi( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + RCLCPP_INFO(get_logger(), "** Reset ROI service called **"); + + if (mDepthDisabled) { + std::string err_msg = + "Error while resetting ZED SDK region of interest: depth processing " + "is " + "disabled!"; + + RCLCPP_WARN_STREAM(get_logger(), " * " << err_msg); + + res->message = err_msg; + res->success = false; + return; + } + + sl::Mat empty_roi; + sl::ERROR_CODE err = mZed->setRegionOfInterest(empty_roi); + + if (err != sl::ERROR_CODE::SUCCESS) { + std::string err_msg = + " * Error while resetting ZED SDK region of interest: "; + err_msg += sl::toString(err); + + RCLCPP_WARN_STREAM( + get_logger(), + " * Error while resetting ZED SDK region of interest: " << err_msg); + + mManualRoiEnabled = false; + + res->message = err_msg; + res->success = false; + } else { + RCLCPP_INFO(get_logger(), " * Region of Interest correctly reset."); + + mManualRoiEnabled = false; + + res->message = "Region of Interest correctly reset."; + res->success = true; + return; + } +} + +void ZedCamera::callback_toLL( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + RCLCPP_INFO(get_logger(), "** Map to Lat/Long service called **"); + + if (!mGnssFusionEnabled) { + RCLCPP_WARN(get_logger(), " * GNSS fusion is not enabled"); + return; + } + + if (mFusedPosTrackingStatus.gnss_fusion_status != sl::GNSS_FUSION_STATUS::OK) { + RCLCPP_WARN(get_logger(), " * GNSS fusion is not yet ready"); + return; + } + + sl::Translation map_pt; + map_pt.x = req->map_point.x; + map_pt.y = req->map_point.y; + map_pt.z = req->map_point.z; + + sl::GeoPose geo_pose; + sl::Pose map_pose; + map_pose.pose_data.setIdentity(); + map_pose.pose_data.setTranslation(map_pt); + mFusion.Camera2Geo(map_pose, geo_pose); + + res->ll_point.altitude = geo_pose.latlng_coordinates.getAltitude(); + res->ll_point.latitude = geo_pose.latlng_coordinates.getLatitude(false); + res->ll_point.longitude = geo_pose.latlng_coordinates.getLongitude(false); + + RCLCPP_INFO( + get_logger(), + "* Converted the MAP point (%.2fm,%.2fm,%.2fm)to GeoPoint " + "%.6f°,%.6f° / %.2f m", + req->map_point.x, req->map_point.y, req->map_point.z, + geo_pose.latlng_coordinates.getLatitude(false), + geo_pose.latlng_coordinates.getLongitude(false), + geo_pose.latlng_coordinates.getAltitude()); +} + +void ZedCamera::callback_fromLL( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + RCLCPP_INFO(get_logger(), "** Lat/Long to Map service called **"); + + if (!mGnssFusionEnabled) { + RCLCPP_WARN(get_logger(), " * GNSS fusion is not enabled"); + return; + } + + if (mFusedPosTrackingStatus.gnss_fusion_status != + sl::GNSS_FUSION_STATUS::OK) + { + RCLCPP_WARN(get_logger(), " * GNSS fusion is not ready"); + return; + } + + sl::LatLng ll_pt; + ll_pt.setCoordinates( + req->ll_point.latitude, req->ll_point.longitude, + req->ll_point.altitude, false); + + sl::Pose sl_pt_cam; + mFusion.Geo2Camera(ll_pt, sl_pt_cam); + + // the point is already in the MAP Frame as it is converted from a GeoPoint + res->map_point.x = sl_pt_cam.getTranslation().x; + res->map_point.y = sl_pt_cam.getTranslation().y; + res->map_point.z = sl_pt_cam.getTranslation().z; + + RCLCPP_INFO( + get_logger(), + "* Converted the GeoPoint %.6f°,%.6f° / %.2f m to MAP point " + "(%.2fm,%.2fm,%.2fm)", + ll_pt.getLatitude(false), ll_pt.getLongitude(false), + ll_pt.getAltitude(), res->map_point.x, res->map_point.y, + res->map_point.z); +} + +void ZedCamera::callback_clock( + const rosgraph_msgs::msg::Clock::SharedPtr msg) +{ + DEBUG_SIM("=== CLOCK CALLBACK ==="); + rclcpp::Time msg_time(msg->clock, RCL_ROS_TIME); + + try { + if (msg_time != mLastClock) { + mClockAvailable = true; + DEBUG_SIM("Received an updated '/clock' message."); + } else { + mClockAvailable = false; + DEBUG_SIM("Received a NOT updated '/clock' message."); + } + mLastClock = msg_time; + } catch (...) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error comparing clock messages: " + << static_cast(msg_time.get_clock_type()) + << " vs " + << static_cast(mLastClock.get_clock_type())); + + mClockAvailable = false; + } +} + +void ZedCamera::processRtRoi(rclcpp::Time ts) +{ + if (!mAutoRoiEnabled && !mManualRoiEnabled) { + mAutoRoiStatus = sl::REGION_OF_INTEREST_AUTO_DETECTION_STATE::NOT_ENABLED; + return; + } + + if (mAutoRoiEnabled) { + auto prevStatus = mAutoRoiStatus; + mAutoRoiStatus = mZed->getRegionOfInterestAutoDetectionStatus(); + DEBUG_STREAM_ROI("Automatic ROI Status:" << sl::toString(mAutoRoiStatus)); + if (prevStatus == + sl::REGION_OF_INTEREST_AUTO_DETECTION_STATE::RUNNING && + mAutoRoiStatus == + sl::REGION_OF_INTEREST_AUTO_DETECTION_STATE::READY) + { + RCLCPP_INFO( + get_logger(), + "Region of interest auto detection is done!"); + } + } + + if (mAutoRoiStatus == sl::REGION_OF_INTEREST_AUTO_DETECTION_STATE::READY || + mManualRoiEnabled) + { + uint8_t subCount = 0; + + try { + if (_nitrosDisabled) { + subCount = mPubRoiMask.getNumSubscribers(); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + subCount = count_subscribers(mRoiMaskTopic); +#endif + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("processRtRoi: Exception while counting subscribers"); + return; + } + + if (subCount > 0) { + DEBUG_ROI("Retrieve ROI Mask"); + sl::Mat roi_mask; + mZed->getRegionOfInterest(roi_mask); + + DEBUG_ROI("Publish ROI Mask"); + + if (_nitrosDisabled) { + publishImageWithInfo( + roi_mask, mPubRoiMask, mPubRoiMaskCamInfo, mPubRoiMaskCamInfoTrans, mLeftCamInfoMsg, + mLeftCamOptFrameId, ts); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + roi_mask, mNitrosPubRoiMask, mPubRoiMaskCamInfo, mPubRoiMaskCamInfoTrans, mLeftCamInfoMsg, + mLeftCamOptFrameId, ts); +#endif + } + } + } +} + +bool ZedCamera::startStreamingServer() +{ + DEBUG_STR("Starting streaming server"); + + if (mZed->isStreamingEnabled()) { + mZed->disableStreaming(); + RCLCPP_WARN(get_logger(), "A streaming server was already running and has been stopped"); + } + + sl::StreamingParameters params; + params.adaptative_bitrate = mStreamingServerAdaptiveBitrate; + params.bitrate = mStreamingServerBitrate; + params.chunk_size = mStreamingServerChunckSize; + params.codec = mStreamingServerCodec; + params.gop_size = mStreamingServerGopSize; + params.port = mStreamingServerPort; + params.target_framerate = mStreamingServerTargetFramerate; + + sl::ERROR_CODE res; + res = mZed->enableStreaming(params); + if (res != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error starting the Streaming server: " << sl::toString( + res) << " - " << sl::toVerbose(res)); + mStreamingServerRunning = false; + } else { + mStreamingServerRunning = true; + RCLCPP_INFO(get_logger(), "Streaming server started"); + } + return mStreamingServerRunning; +} + +void ZedCamera::stopStreamingServer() +{ + if (mZed->isStreamingEnabled()) { + mZed->disableStreaming(); + RCLCPP_INFO(get_logger(), "Streaming server stopped"); + } else { + RCLCPP_WARN(get_logger(), "A streaming server was not enabled."); + } + + mStreamingServerRunning = false; + mStreamingServerRequired = false; +} + +void ZedCamera::publishHealthStatus() +{ + if (!mPubHealthStatus) { + return; + } + + if (mImageValidityCheck <= 0 || !mPublishStatus) { + return; + } + + size_t sub_count = 0; + try { + sub_count = mPubHealthStatus->get_subscription_count(); + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("publishHealthStatus: Exception while counting subscribers"); + return; + } + + if (sub_count == 0) { + return; + } + + sl::HealthStatus status = mZed->getHealthStatus(); + auto msg = std::make_unique(); + msg->header.stamp = mUsePubTimestamps ? + get_clock()->now() : + mFrameTimestamp; + msg->header.frame_id = mBaseFrameId; + msg->serial_number = mCamSerialNumber; + msg->camera_name = mCameraName; + msg->low_image_quality = status.low_image_quality; + msg->low_lighting = status.low_lighting; + msg->low_depth_reliability = status.low_depth_reliability; + msg->low_motion_sensors_reliability = + status.low_motion_sensors_reliability; + + mPubHealthStatus->publish(std::move(msg)); +} + +bool ZedCamera::publishSvoStatus(uint64_t frame_ts) +{ + if (!mSvoMode) { + return false; + } + + if (!mPubSvoStatus) { + return false; + } + + size_t subCount = 0; + try { + subCount = mPubSvoStatus->get_subscription_count(); + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("publishSvoStatus: Exception while counting subscribers"); + return false; + } + + if (subCount > 0) { + auto msg = std::make_unique(); + + // ----> Fill the status message + msg->file_name = mSvoFilepath; + msg->frame_id = mZed->getSVOPosition(); + msg->total_frames = mZed->getSVONumberOfFrames(); + msg->frame_ts = frame_ts; + + if (mSvoPause) { + msg->status = zed_msgs::msg::SvoStatus::STATUS_PAUSED; + } else if (mGrabStatus == sl::ERROR_CODE::END_OF_SVOFILE_REACHED) { + msg->frame_id = msg->total_frames - 1; + msg->status = zed_msgs::msg::SvoStatus::STATUS_END; + } else { + msg->status = zed_msgs::msg::SvoStatus::STATUS_PLAYING; + } + + msg->loop_active = mSvoLoop; + msg->loop_count = mSvoLoopCount; + msg->real_time_mode = mSvoRealtime; + // <---- Fill the status message + + // Publish the message + if (mPubSvoStatus) {mPubSvoStatus->publish(std::move(msg));} + return true; + } + return false; +} + +void ZedCamera::callback_pubHeartbeat() +{ + if (!mPubHeartbeatStatus) { + return; + } + + if (!mPublishStatus) { + return; + } + + if (mThreadStop) { + return; + } + + // ----> Count the subscribers + size_t sub_count = 0; + try { + sub_count = mPubHeartbeatStatus->get_subscription_count(); + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("publishHeartbeat: Exception while counting subscribers"); + return; + } + + if (sub_count == 0) { + return; + } + // <---- Count the subscribers + + // ----> Fill the message + auto msg = std::make_unique(); + msg->beat_count = ++mHeartbeatCount; + msg->camera_sn = mCamSerialNumber; + msg->full_name = this->get_fully_qualified_name(); + msg->node_name = this->get_name(); + msg->node_ns = this->get_namespace(); + msg->simul_mode = mSimMode; + msg->svo_mode = mSvoMode; + // <---- Fill the message + + // Publish the heartbeat + if (mPubHeartbeatStatus) {mPubHeartbeatStatus->publish(std::move(msg));} +} + +void ZedCamera::publishClock(const sl::Timestamp & ts) +{ + DEBUG_COMM("Publishing clock"); + + if (!mPubClock) { + return; + } + + size_t subCount = 0; + try { + subCount = mPubClock->get_subscription_count(); + } catch (...) { + rcutils_reset_error(); + DEBUG_COMM("publishClock: Exception while counting subscribers"); + return; + } + + if (subCount == 0) { + return; + } + + auto msg = std::make_unique(); + msg->clock = sl_tools::slTime2Ros(ts); + + if (mPubClock) {mPubClock->publish(std::move(msg));} +} + +} // namespace stereolabs + +#include "rclcpp_components/register_node_macro.hpp" + +// Register the component with class_loader. +// This acts as a sort of entry point, allowing the component to be discoverable +// when its library is being loaded into a running process. +RCLCPP_COMPONENTS_REGISTER_NODE(stereolabs::ZedCamera) diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_objdet.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_objdet.cpp new file mode 100644 index 0000000000..46b6e6b02f --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_objdet.cpp @@ -0,0 +1,1211 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zed_camera_component.hpp" +#include "sl_logging.hpp" +#include "sl_tools.hpp" + +namespace stereolabs +{ + +void ZedCamera::getOdParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== OBJECT DETECTION parameters ==="); + if (sl_tools::isZED(mCamUserModel)) { + RCLCPP_WARN(get_logger(), "!!! OD parameters are not used with ZED!!!"); + return; + } + + sl_tools::getParam( + shared_from_this(), "object_detection.od_enabled", + mObjDetEnabled, mObjDetEnabled, + " * Object Det. enabled: "); + + sl_tools::getParam( + shared_from_this(), + "object_detection.allow_reduced_precision_inference", + mObjDetReducedPrecision, mObjDetReducedPrecision); + RCLCPP_INFO_STREAM( + get_logger(), + " * Object Det. allow reduced precision: " + << (mObjDetReducedPrecision ? "TRUE" : "FALSE")); + sl_tools::getParam( + shared_from_this(), "object_detection.max_range", + mObjDetMaxRange, mObjDetMaxRange, + " * Object Det. maximum range [m]: ", false, 0.1, 40.0); + sl_tools::getParam( + shared_from_this(), "object_detection.prediction_timeout", + mObjDetPredTimeout, mObjDetPredTimeout, + " * Object Det. prediction timeout [sec]: ", false, 0.0, 300.0); + sl_tools::getParam( + shared_from_this(), "object_detection.enable_tracking", + mObjDetTracking, mObjDetTracking); + RCLCPP_INFO_STREAM( + get_logger(), " * Object Det. tracking: " + << (mObjDetTracking ? "TRUE" : "FALSE")); + + sl_tools::getEnumParam( + shared_from_this(), "object_detection.filtering_mode", "NONE", + sl::OBJECT_FILTERING_MODE::NONE, + sl::OBJECT_FILTERING_MODE::LAST, mObjFilterMode, + " * Object Filtering mode: "); + + // ----> Object Detection model + if (!sl_tools::getEnumParam( + shared_from_this(), "object_detection.detection_model", + "MULTI_CLASS_BOX_FAST", + sl::OBJECT_DETECTION_MODEL::MULTI_CLASS_BOX_FAST, + sl::OBJECT_DETECTION_MODEL::LAST, mObjDetModel)) + { + RCLCPP_ERROR(get_logger(), "Stopping the node."); + exit(EXIT_FAILURE); + } + if (mObjDetModel == sl::OBJECT_DETECTION_MODEL::CUSTOM_BOX_OBJECTS) { + RCLCPP_ERROR_STREAM( + get_logger(), + "The value of the parameter 'object_detection.detection_model' is not supported: '" + << sl::toString(mObjDetModel).c_str() << "'. Stopping the node"); + exit(EXIT_FAILURE); + } + RCLCPP_INFO_STREAM( + get_logger(), " * Object Det. model: " + << sl::toString(mObjDetModel).c_str()); + + if (mObjDetModel == sl::OBJECT_DETECTION_MODEL::CUSTOM_YOLOLIKE_BOX_OBJECTS) { + mUsingCustomOd = true; + } else { + mUsingCustomOd = false; + } + // <---- Object Detection model + + if (mUsingCustomOd) { + getCustomOdParams(); + } else { + // ----> MultiClassBox parameters + sl_tools::getParam( + shared_from_this(), + "object_detection.class.people.enabled", + mObjDetPeopleEnable, mObjDetPeopleEnable, + " * MultiClassBox people: ", true); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.vehicle.enabled", + mObjDetVehiclesEnable, mObjDetVehiclesEnable, + " * MultiClassBox vehicles: ", true); + sl_tools::getParam( + shared_from_this(), "object_detection.class.bag.enabled", + mObjDetBagsEnable, mObjDetBagsEnable, + " * MultiClassBox bags: ", true); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.animal.enabled", + mObjDetAnimalsEnable, mObjDetAnimalsEnable, + " * MultiClassBox animals: ", true); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.electronics.enabled", + mObjDetElectronicsEnable, mObjDetElectronicsEnable, + " * MultiClassBox electronics: ", true); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.fruit_vegetable.enabled", + mObjDetFruitsEnable, mObjDetFruitsEnable, + " * MultiClassBox fruits and vegetables: ", true); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.sport.enabled", + mObjDetSportEnable, mObjDetSportEnable, + " * MultiClassBox sport-related objects: ", true); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.people.confidence_threshold", + mObjDetPeopleConf, mObjDetPeopleConf, + " * MultiClassBox people confidence: ", true, 0.0, 100.0); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.vehicle.confidence_threshold", + mObjDetVehiclesConf, mObjDetVehiclesConf, + " * MultiClassBox vehicles confidence: ", true, 0.0, 100.0); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.bag.confidence_threshold", + mObjDetBagsConf, mObjDetBagsConf, + " * MultiClassBox bags confidence: ", true, 0.0, 100.0); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.animal.confidence_threshold", + mObjDetAnimalsConf, mObjDetAnimalsConf, + " * MultiClassBox animals confidence: ", true, 0.0, 100.0); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.electronics.confidence_threshold", + mObjDetElectronicsConf, mObjDetElectronicsConf, + " * MultiClassBox electronics confidence: ", true, 0.0, 100.0); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.fruit_vegetable.confidence_threshold", + mObjDetFruitsConf, mObjDetFruitsConf, + " * MultiClassBox fruits and vegetables confidence: ", true, 0.0, 100.0); + sl_tools::getParam( + shared_from_this(), + "object_detection.class.sport.confidence_threshold", + mObjDetSportConf, mObjDetSportConf, + " * MultiClassBox sport-related objects confidence: ", true, 0.0, 100.0); + // <---- MultiClassBox parameters + } +} + +void ZedCamera::getCustomOdParams() +{ + sl_tools::getParam( + shared_from_this(), "object_detection.custom_onnx_file", + mYoloOnnxPath, mYoloOnnxPath, " * Custom ONNX file: "); + if (mYoloOnnxPath.empty()) { + RCLCPP_ERROR_STREAM( + get_logger(), + "The parameter 'object_detection.custom_onnx_file' is empty. " + "Please check the value in the YAML file."); + exit(EXIT_FAILURE); + } + sl_tools::getParam( + shared_from_this(), + "object_detection.custom_onnx_input_size", mYoloOnnxSize, + mYoloOnnxSize, " * Custom ONNX input size: ", false, 128, 2048); + sl_tools::getParam( + shared_from_this(), + "object_detection.custom_class_count", mCustomClassCount, + mCustomClassCount, " * Custom ONNX class count: ", false, 1, 999); + + for (int i = 0; i < mCustomClassCount; i++) { + std::string param_name; + std::string label = ""; + int class_id = i; + + std::stringstream class_prefix; + class_prefix << "class_"; + class_prefix.width(3); + class_prefix.fill('0'); + class_prefix << i; + + std::string param_prefix = std::string("object_detection.") + class_prefix.str() + "."; + + param_name = param_prefix + "label"; + sl_tools::getParam( + shared_from_this(), param_name, label, label, std::string( + " * ") + param_name + ": ", false); + + param_name = param_prefix + "model_class_id"; + sl_tools::getParam( + shared_from_this(), param_name, class_id, class_id, std::string( + " * ") + param_name + ": ", false, 0, 999); + + mCustomClassIdMap[class_prefix.str()] = class_id; // Update the class prefix to class_id mapping + DEBUG_STREAM_OD(" Mapped '" << class_prefix.str() << "' to ID '" << class_id << "'"); + mCustomLabels[class_id] = label; // Update the class id to label mapping + DEBUG_STREAM_OD(" Mapped ID '" << class_id << "' to '" << label << "'"); + + sl::CustomObjectDetectionProperties customOdProperties; + + param_name = param_prefix + "enabled"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.enabled, customOdProperties.enabled, std::string( + " * ") + param_name + ": ", true); + + param_name = param_prefix + "confidence_threshold"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.detection_confidence_threshold, customOdProperties.detection_confidence_threshold, std::string( + " * ") + param_name + ": ", true, 0.0f, 100.0f); + param_name = param_prefix + "is_grounded"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.is_grounded, customOdProperties.is_grounded, std::string( + " * ") + param_name + ": ", true); + param_name = param_prefix + "is_static"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.is_static, customOdProperties.is_static, std::string( + " * ") + param_name + ": ", true); + param_name = param_prefix + "tracking_timeout"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.tracking_timeout, customOdProperties.tracking_timeout, std::string( + " * ") + param_name + ": ", true, -1.0f, + 300.0f); + param_name = param_prefix + "tracking_max_dist"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.tracking_max_dist, customOdProperties.tracking_max_dist, std::string( + " * ") + param_name + ": ", true, -1.0f, + 100.0f); + param_name = param_prefix + "max_box_width_normalized"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.max_box_width_normalized, customOdProperties.max_box_width_normalized, std::string( + " * ") + param_name + ": ", true, -1.0f, + 1.0f); + param_name = param_prefix + "min_box_width_normalized"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.min_box_width_normalized, customOdProperties.min_box_width_normalized, std::string( + " * ") + param_name + ": ", true, -1.0f, + 1.0f); + param_name = param_prefix + "max_box_height_normalized"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.max_box_height_normalized, customOdProperties.max_box_height_normalized, std::string( + " * ") + param_name + ": ", true, -1.0f, + 1.0f); + param_name = param_prefix + "min_box_height_normalized"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.min_box_height_normalized, customOdProperties.min_box_height_normalized, std::string( + " * ") + param_name + ": ", true, -1.0f, + 1.0f); + param_name = param_prefix + "max_box_width_meters"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.max_box_width_meters, customOdProperties.max_box_width_meters, + std::string(" * ") + param_name + ": ", true, -1.0f, + 10000.0f); + param_name = param_prefix + "min_box_width_meters"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.min_box_width_meters, customOdProperties.min_box_width_meters, + std::string(" * ") + param_name + ": ", true, -1.0f, + 10000.0f); + param_name = param_prefix + "max_box_height_meters"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.max_box_height_meters, customOdProperties.max_box_height_meters, std::string( + " * ") + param_name + ": ", true, -1.0f, + 10000.0f); + param_name = param_prefix + "max_allowed_acceleration"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.max_allowed_acceleration, customOdProperties.max_allowed_acceleration, std::string( + " * ") + param_name + ": ", true, 0.0f, + 100000.0f); + param_name = param_prefix + "velocity_smoothing_factor"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.object_tracking_parameters.velocity_smoothing_factor, customOdProperties.object_tracking_parameters.velocity_smoothing_factor, std::string( + " * ") + param_name + ": ", true, 0.0f, + 1.0f); + param_name = param_prefix + "min_velocity_threshold"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.object_tracking_parameters.min_velocity_threshold, customOdProperties.object_tracking_parameters.min_velocity_threshold, std::string( + " * ") + param_name + ": ", true, 0.0f, + 100.0f); + param_name = param_prefix + "prediction_timeout_s"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.object_tracking_parameters.prediction_timeout_s, customOdProperties.object_tracking_parameters.prediction_timeout_s, std::string( + " * ") + param_name + ": ", true, 0.0f, + 100.0f); + param_name = param_prefix + "min_confirmation_time_s"; + sl_tools::getParam( + shared_from_this(), param_name, + customOdProperties.object_tracking_parameters.min_confirmation_time_s, customOdProperties.object_tracking_parameters.min_confirmation_time_s, std::string( + " * ") + param_name + ": ", true, 0.0f, + 100.0f); + + param_name = param_prefix + "object_acceleration_preset"; + sl_tools::getEnumParam( + shared_from_this(), param_name, "DEFAULT", + sl::OBJECT_ACCELERATION_PRESET::DEFAULT, + sl::OBJECT_ACCELERATION_PRESET::LAST, + customOdProperties.object_tracking_parameters.object_acceleration_preset, + std::string(" * ") + param_name + ": "); + + mCustomOdProperties[class_id] = customOdProperties; // Update the Custom OD Properties information + } + +} + +bool ZedCamera::handleOdDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + DEBUG_OD("handleOdDynamicParams"); + + if (param.get_name() == "object_detection.class.people.enabled") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mObjDetPeopleEnable = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mObjDetPeopleEnable ? "TRUE" : "FALSE")); + } else if (param.get_name() == "object_detection.class.vehicle.enabled") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mObjDetVehiclesEnable = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mObjDetVehiclesEnable ? "TRUE" : "FALSE")); + } else if (param.get_name() == "object_detection.class.bag.enabled") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mObjDetBagsEnable = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mObjDetBagsEnable ? "TRUE" : "FALSE")); + } else if (param.get_name() == "object_detection.class.animal.enabled") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mObjDetAnimalsEnable = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mObjDetAnimalsEnable ? "TRUE" : "FALSE")); + } else if (param.get_name() == + "object_detection.class.electronics.enabled") + { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mObjDetElectronicsEnable = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mObjDetElectronicsEnable ? "TRUE" : "FALSE")); + } else if (param.get_name() == + "object_detection.class.fruit_vegetable.enabled") + { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mObjDetFruitsEnable = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mObjDetFruitsEnable ? "TRUE" : "FALSE")); + } else if (param.get_name() == "object_detection.class.sport.enabled") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mObjDetSportEnable = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mObjDetSportEnable ? "TRUE" : "FALSE")); + } else if (param.get_name() == "object_detection.class.people.confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange(param, mObjDetPeopleConf, 0.0, 100.0, result, get_logger())) { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mObjDetPeopleConf); + } else if (param.get_name() == "object_detection.class.vehicle.confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange(param, mObjDetVehiclesConf, 0.0, 100.0, result, get_logger())) { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mObjDetVehiclesConf); + } else if (param.get_name() == "object_detection.class.bag.confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange(param, mObjDetBagsConf, 0.0, 100.0, result, get_logger())) { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mObjDetBagsConf); + } else if (param.get_name() == "object_detection.class.animal.confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange(param, mObjDetAnimalsConf, 0.0, 100.0, result, get_logger())) { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mObjDetAnimalsConf); + } else if (param.get_name() == "object_detection.class.electronics.confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + if (!sl_tools::checkParamRange( + param, mObjDetElectronicsConf, 0.0, 100.0, result, + get_logger())) + { + return false; + } + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mObjDetElectronicsConf); + } else if (param.get_name() == "object_detection.class.fruit_vegetable.confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange(param, mObjDetFruitsConf, 0.0, 100.0, result, get_logger())) { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mObjDetFruitsConf); + } else if (param.get_name() == "object_detection.class.sport.confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange(param, mObjDetSportConf, 0.0, 100.0, result, get_logger())) { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mObjDetSportConf); + } + + mObjDetRtParamsDirty = true; + return true; +} + +bool ZedCamera::handleCustomOdDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + DEBUG_COMM("handleCustomOdDynamicParams"); + + std::string param_full_name = param.get_name(); + DEBUG_STREAM_COMM("handleCustomOdDynamicParams: Parameter name: " << param_full_name); + + if (param_full_name.find("object_detection.class_") == std::string::npos) { + DEBUG_STREAM_COMM( + "handleCustomOdDynamicParams: Parameter '" << param_full_name << + "' is not a custom object detection parameter"); + return true; + } + + // Get the class ID from the parameter name + std::string class_id_str = param_full_name.substr(param_full_name.find("class_"), 9); + DEBUG_STREAM_COMM("handleCustomOdDynamicParams: Class ID: " << class_id_str); + + auto it = mCustomClassIdMap.find(class_id_str); + if (it == mCustomClassIdMap.end()) { + DEBUG_STREAM_COMM( + "handleCustomOdDynamicParams: Class ID '" + << class_id_str << "' not found"); + return false; + } + int class_id = it->second; + DEBUG_STREAM_COMM("handleCustomOdDynamicParams: Class ID: " << class_id); + + std::string param_name = param_full_name.substr(param_full_name.find_last_of('.') + 1); + DEBUG_STREAM_COMM("handleCustomOdDynamicParams: Custom OD Parameter name: " << param_name); + + if (param_name == "enabled") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].enabled = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mCustomOdProperties[class_id].enabled ? "TRUE" : "FALSE")); + } else if (param_name == "confidence_threshold") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + if (!sl_tools::checkParamRange( + param, mCustomOdProperties[class_id].detection_confidence_threshold, + 0.0f, 100.0f, result, get_logger())) + { + return false; + } + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].detection_confidence_threshold); + } else if (param_name == "is_grounded") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].is_grounded = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mCustomOdProperties[class_id].is_grounded ? "TRUE" : "FALSE")); + } else if (param_name == "is_static") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].is_static = param.as_bool(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << (mCustomOdProperties[class_id].is_static ? "TRUE" : "FALSE")); + } else if (param_name == "tracking_timeout") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].tracking_timeout = param.as_double(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].tracking_timeout); + } else if (param_name == "tracking_max_dist") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].tracking_max_dist = param.as_double(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].tracking_max_dist); + } else if (param_name == "max_box_width_normalized") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].max_box_width_normalized = param.as_double(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].max_box_width_normalized); + } else if (param_name == "min_box_width_normalized") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].min_box_width_normalized = param.as_double(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].min_box_width_normalized); + } else if (param_name == "max_box_height_normalized") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].max_box_height_normalized = param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].max_box_height_normalized); + } else if (param_name == "min_box_height_normalized") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].min_box_height_normalized = param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].min_box_height_normalized); + } else if (param_name == "max_box_width_meters") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].max_box_width_meters = param.as_double(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].max_box_width_meters); + } else if (param_name == "min_box_width_meters") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + + mCustomOdProperties[class_id].min_box_width_meters = param.as_double(); + + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].min_box_width_meters); + } else if (param_name == "max_box_height_meters") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].max_box_height_meters = param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].max_box_height_meters); + } else if (param_name == "max_allowed_acceleration") { + rclcpp::ParameterType + correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].max_allowed_acceleration = param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].max_allowed_acceleration); + } else if (param_name == "velocity_smoothing_factor") { + rclcpp::ParameterType + correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].object_tracking_parameters.velocity_smoothing_factor = + param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].object_tracking_parameters.velocity_smoothing_factor); + } else if (param_name == "min_velocity_threshold") { + rclcpp::ParameterType + correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].object_tracking_parameters.min_velocity_threshold = + param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].object_tracking_parameters.min_velocity_threshold); + } else if (param_name == "prediction_timeout_s") { + rclcpp::ParameterType + correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].object_tracking_parameters.prediction_timeout_s = + param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].object_tracking_parameters.prediction_timeout_s); + } else if (param_name == "min_confirmation_time_s") { + rclcpp::ParameterType + correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = + param.get_name() + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return false; + } + mCustomOdProperties[class_id].object_tracking_parameters.min_confirmation_time_s = + param.as_double(); + DEBUG_STREAM_DYN_PARAMS( + "Parameter '" + << param.get_name() << "' correctly set to " + << mCustomOdProperties[class_id].object_tracking_parameters.min_confirmation_time_s); + } else { + RCLCPP_WARN_STREAM(get_logger(), "Unknown parameter: " << param.get_name()); + } + + mObjDetRtParamsDirty = true; + return true; +} + +bool ZedCamera::startObjDetect() +{ + DEBUG_OD("startObjDetect"); + + if (!sl_tools::isObjDetAvailable(mCamRealModel)) { + RCLCPP_ERROR( + get_logger(), + "Object detection not started. The camera model does not " + "support it with the current version " + "of the " + "SDK"); + return false; + } + + if (mDepthDisabled) { + RCLCPP_WARN( + get_logger(), + "Cannot start Object Detection if " + "`depth.depth_mode` is set to `0` [NONE]"); + return false; + } + + if (!mObjDetEnabled) { + return false; + } + + RCLCPP_INFO(get_logger(), "=== Starting Object Detection ==="); + + sl::ObjectDetectionParameters od_p; + od_p.enable_segmentation = false; + od_p.enable_tracking = mObjDetTracking; + od_p.detection_model = mObjDetModel; + od_p.filtering_mode = mObjFilterMode; + od_p.prediction_timeout_s = mObjDetPredTimeout; + od_p.allow_reduced_precision_inference = mObjDetReducedPrecision; + od_p.max_range = mObjDetMaxRange; + + if (mUsingCustomOd) { + od_p.custom_onnx_dynamic_input_shape = mYoloOnnxSize; + od_p.custom_onnx_file = mYoloOnnxPath; + } + + sl::ERROR_CODE objDetError = mZed->enableObjectDetection(od_p); + if (objDetError != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Object detection error: " << sl::toString(objDetError)); + + mObjDetRunning = false; + return false; + } + + if (!mPubObjDet) { + mPubObjDet = create_publisher( + mObjectDetTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic " << mPubObjDet->get_topic_name()); + } + + mObjDetRunning = true; + return true; +} + +void ZedCamera::stopObjDetect() +{ + if (mObjDetRunning) { + RCLCPP_INFO(get_logger(), "=== Stopping Object Detection ==="); + mObjDetRunning = false; + mObjDetEnabled = false; + mZed->disableObjectDetection(); + + // ----> Send an empty message to indicate that no more objects are tracked + // (e.g clean RVIZ2) + auto objMsg = std::make_unique(); + + objMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + objMsg->header.frame_id = mLeftCamFrameId; + + objMsg->objects.clear(); + + DEBUG_STREAM_OD( + "Publishing EMPTY OBJ message " + << mPubObjDet->get_topic_name()); + try { + mPubObjDet->publish(std::move(objMsg)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what() ); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + // <---- Send an empty message to indicate that no more objects are tracked + // (e.g clean RVIZ2) + } +} + +void ZedCamera::processDetectedObjects(rclcpp::Time t) +{ + size_t objdet_sub_count = 0; + + try { + if (mPubObjDet) { + objdet_sub_count = count_subscribers(mPubObjDet->get_topic_name()); + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_OD( + "processDetectedObjects: Exception while counting subscribers"); + return; + } + + if (objdet_sub_count < 1) { + mObjDetSubscribed = false; + return; + } + + sl_tools::StopWatch odElabTimer(get_clock()); + + mObjDetSubscribed = true; + + sl::Objects objects; + sl::ERROR_CODE objDetRes; + + // ----> Update runtime parameters only when changed (B2 optimization) + if (mObjDetRtParamsDirty) { + if (!mUsingCustomOd || ZED_SDK_MAJOR_VERSION < 5) { + sl::ObjectDetectionRuntimeParameters objectTracker_parameters_rt; + objectTracker_parameters_rt.detection_confidence_threshold = 50.0f; + mObjDetFilter.clear(); + mObjDetClassConfMap.clear(); + if (mObjDetPeopleEnable) { + mObjDetFilter.push_back(sl::OBJECT_CLASS::PERSON); + mObjDetClassConfMap[sl::OBJECT_CLASS::PERSON] = mObjDetPeopleConf; + } + if (mObjDetVehiclesEnable) { + mObjDetFilter.push_back(sl::OBJECT_CLASS::VEHICLE); + mObjDetClassConfMap[sl::OBJECT_CLASS::VEHICLE] = mObjDetVehiclesConf; + } + if (mObjDetBagsEnable) { + mObjDetFilter.push_back(sl::OBJECT_CLASS::BAG); + mObjDetClassConfMap[sl::OBJECT_CLASS::BAG] = mObjDetBagsConf; + } + if (mObjDetAnimalsEnable) { + mObjDetFilter.push_back(sl::OBJECT_CLASS::ANIMAL); + mObjDetClassConfMap[sl::OBJECT_CLASS::ANIMAL] = mObjDetAnimalsConf; + } + if (mObjDetElectronicsEnable) { + mObjDetFilter.push_back(sl::OBJECT_CLASS::ELECTRONICS); + mObjDetClassConfMap[sl::OBJECT_CLASS::ELECTRONICS] = mObjDetElectronicsConf; + } + if (mObjDetFruitsEnable) { + mObjDetFilter.push_back(sl::OBJECT_CLASS::FRUIT_VEGETABLE); + mObjDetClassConfMap[sl::OBJECT_CLASS::FRUIT_VEGETABLE] = + mObjDetFruitsConf; + } + if (mObjDetSportEnable) { + mObjDetFilter.push_back(sl::OBJECT_CLASS::SPORT); + mObjDetClassConfMap[sl::OBJECT_CLASS::SPORT] = mObjDetSportConf; + } + objectTracker_parameters_rt.object_class_filter = mObjDetFilter; + objectTracker_parameters_rt.object_class_detection_confidence_threshold = mObjDetClassConfMap; + mZed->setObjectDetectionRuntimeParameters(objectTracker_parameters_rt); + } +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 50 + else { + sl::CustomObjectDetectionRuntimeParameters custom_objectTracker_parameters_rt; + custom_objectTracker_parameters_rt.object_class_detection_properties = mCustomOdProperties; + mZed->setCustomObjectDetectionRuntimeParameters(custom_objectTracker_parameters_rt); + } +#endif + mObjDetRtParamsDirty = false; + } + // <---- Update runtime parameters only when changed + + objDetRes = mZed->retrieveObjects(objects); + + if (objDetRes != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Object Detection error: " << sl::toString(objDetRes)); + return; + } + + if (!objects.is_new) { // Async object detection. Update data only if new + // detection is available + DEBUG_OD("No new detected objects"); + return; + } + + DEBUG_STREAM_OD("Detected " << objects.object_list.size() << " objects"); + + size_t objCount = objects.object_list.size(); + + auto objMsg = std::make_unique(); + + objMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + objMsg->header.frame_id = mLeftCamFrameId; + + objMsg->objects.resize(objCount); + + size_t idx = 0; + for (const auto & data : objects.object_list) { + if (!mUsingCustomOd) { + objMsg->objects[idx].label = sl::toString(data.label).c_str(); + objMsg->objects[idx].sublabel = sl::toString(data.sublabel).c_str(); + } else { + auto it = mCustomLabels.find(data.raw_label); + objMsg->objects[idx].label = (it != mCustomLabels.end()) ? it->second : std::string(); + objMsg->objects[idx].sublabel = std::to_string(data.raw_label); + } + + objMsg->objects[idx].label_id = data.id; + objMsg->objects[idx].confidence = data.confidence; + + DEBUG_STREAM_OD( + " * Object ID:" << data.id << " - " << + objMsg->objects[idx].label << " [" << objMsg->objects[idx].sublabel << "] - Confidence: " << + objMsg->objects[idx].confidence); + + memcpy( + &(objMsg->objects[idx].position[0]), &(data.position[0]), + 3 * sizeof(float)); + memcpy( + &(objMsg->objects[idx].position_covariance[0]), + &(data.position_covariance[0]), 6 * sizeof(float)); + memcpy( + &(objMsg->objects[idx].velocity[0]), &(data.velocity[0]), + 3 * sizeof(float)); + + objMsg->objects[idx].tracking_available = mObjDetTracking; + objMsg->objects[idx].tracking_state = + static_cast(data.tracking_state); + objMsg->objects[idx].action_state = + static_cast(data.action_state); + + if (data.bounding_box_2d.size() == 4) { + memcpy( + &(objMsg->objects[idx].bounding_box_2d.corners[0]), + &(data.bounding_box_2d[0]), 8 * sizeof(unsigned int)); + } + if (data.bounding_box.size() == 8) { + memcpy( + &(objMsg->objects[idx].bounding_box_3d.corners[0]), + &(data.bounding_box[0]), 24 * sizeof(float)); + } + + memcpy( + &(objMsg->objects[idx].dimensions_3d[0]), &(data.dimensions[0]), + 3 * sizeof(float)); + + if (data.head_bounding_box_2d.size() == 4) { + memcpy( + &(objMsg->objects[idx].head_bounding_box_2d.corners[0]), + &(data.head_bounding_box_2d[0]), 8 * sizeof(unsigned int)); + } + if (data.head_bounding_box.size() == 8) { + memcpy( + &(objMsg->objects[idx].head_bounding_box_3d.corners[0]), + &(data.head_bounding_box[0]), 24 * sizeof(float)); + } + + memcpy( + &(objMsg->objects[idx].head_position[0]), &(data.head_position[0]), + 3 * sizeof(float)); + + objMsg->objects[idx].skeleton_available = false; + // at the end of the loop + idx++; + } + + // DEBUG_STREAM_OD("Publishing OBJ DET message"); + try { + mPubObjDet->publish(std::move(objMsg)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + + // ----> Diagnostic information update + mObjDetElabMean_sec->addValue(odElabTimer.toc()); + mObjDetPeriodMean_sec->addValue(mOdFreqTimer.toc()); + mOdFreqTimer.tic(); + // <---- Diagnostic information update +} + +} // namespace stereolabs diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_video_depth.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_video_depth.cpp new file mode 100644 index 0000000000..49e7401b2b --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera/src/zed_camera_component_video_depth.cpp @@ -0,0 +1,3288 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zed_camera_component.hpp" +#include "sl_logging.hpp" +#include "sl_tools.hpp" + +#include +#include +#include +#include + +#include + +namespace stereolabs +{ + +void ZedCamera::initVideoDepthPublishers() +{ + // ----> Topic name roots and suffixes + const std::string sens_rgb = "rgb/"; + const std::string sens_left = "left/"; + const std::string sens_right = "right/"; + const std::string sens_stereo = "stereo/"; + const std::string rectified = "rect/"; + const std::string raw = "raw/"; + const std::string color = "color/"; + const std::string gray = "gray/"; + const std::string type_image = "image"; + + // Helper to build topic names + auto make_topic = + [&](const std::string & sensor, const std::string & color_mode, const std::string & rect_raw, + const std::string & type) { + std::string topic = mTopicRoot + sensor + color_mode + rect_raw + type; + return get_node_topics_interface()->resolve_topic_name(topic); + }; + + // Image topics + mLeftTopic = make_topic(sens_left, color, rectified, type_image); + mLeftRawTopic = make_topic(sens_left, color, raw, type_image); + mRightTopic = make_topic(sens_right, color, rectified, type_image); + mRightRawTopic = make_topic(sens_right, color, raw, type_image); + mRgbTopic = make_topic(sens_rgb, color, rectified, type_image); + mRgbRawTopic = make_topic(sens_rgb, color, raw, type_image); + mStereoTopic = make_topic(sens_stereo, color, rectified, type_image); + mStereoRawTopic = make_topic(sens_stereo, color, raw, type_image); + mLeftGrayTopic = make_topic(sens_left, gray, rectified, type_image); + mLeftRawGrayTopic = make_topic(sens_left, gray, raw, type_image); + mRightGrayTopic = make_topic(sens_right, gray, rectified, type_image); + mRightRawGrayTopic = make_topic(sens_right, gray, raw, type_image); + mRgbGrayTopic = make_topic(sens_rgb, gray, rectified, type_image); + mRgbRawGrayTopic = make_topic(sens_rgb, gray, raw, type_image); + + // Depth topics + mDisparityTopic = mTopicRoot + "disparity/disparity_image"; + mDepthTopic = mTopicRoot + "depth/depth_registered"; + mDepthInfoTopic = mTopicRoot + "depth/depth_info"; + mConfMapTopic = mTopicRoot + "confidence/confidence_map"; + mPointcloudTopic = mTopicRoot + "point_cloud/cloud_registered"; + if (mOpenniDepthMode) { + RCLCPP_INFO(get_logger(), "OpenNI depth mode activated -> Units: mm, Encoding: MONO16"); + } + mDisparityTopic = get_node_topics_interface()->resolve_topic_name(mDisparityTopic); + mDepthTopic = get_node_topics_interface()->resolve_topic_name(mDepthTopic); + mDepthInfoTopic = get_node_topics_interface()->resolve_topic_name(mDepthInfoTopic); + mConfMapTopic = get_node_topics_interface()->resolve_topic_name(mConfMapTopic); + mPointcloudTopic = get_node_topics_interface()->resolve_topic_name(mPointcloudTopic); + + // ROI mask topic + mRoiMaskTopic = mTopicRoot + "roi_mask/image"; + mRoiMaskTopic = get_node_topics_interface()->resolve_topic_name(mRoiMaskTopic); + + // ----> Camera publishers + auto qos = mQos.get_rmw_qos_profile(); + + // Camera publishers + if (_nitrosDisabled) { + + // Publishers logging + auto log_cam_pub = [&](const auto & pub) { + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << pub.getTopic()); + std::vector transports{}; + //transports = image_transport::getLoadableTransports(); + try { + transports = image_transport::getDeclaredTransports(); + } catch (const std::exception & e) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Failed to get declared transports: " << e.what()); + } catch (...) { + RCLCPP_ERROR(get_logger(), "Unknown error while getting declared transports"); + } + + for (const auto & transport : transports) { + std::string transport_copy = transport; + auto pos = transport_copy.find('/'); + if (pos != std::string::npos) { + transport_copy.erase(0, pos); + } + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << pub.getTopic() << transport_copy + << " [image_transport]"); + } + }; + + if (mPublishImgRgb) { + mPubRgb = image_transport::create_publisher(this, mRgbTopic, qos); + log_cam_pub(mPubRgb); + if (mPublishImgGray) { + mPubRgbGray = image_transport::create_publisher(this, mRgbGrayTopic, qos); + log_cam_pub(mPubRgbGray); + } + if (mPublishImgRaw) { + mPubRawRgb = image_transport::create_publisher(this, mRgbRawTopic, qos); + log_cam_pub(mPubRawRgb); + } + if (mPublishImgRaw && mPublishImgGray) { + mPubRawRgbGray = image_transport::create_publisher(this, mRgbRawGrayTopic, qos); + log_cam_pub(mPubRawRgbGray); + } + } + if (mPublishImgLeftRight) { + mPubLeft = image_transport::create_publisher(this, mLeftTopic, qos); + log_cam_pub(mPubLeft); + mPubRight = image_transport::create_publisher(this, mRightTopic, qos); + log_cam_pub(mPubRight); + if (mPublishImgGray) { + mPubLeftGray = image_transport::create_publisher(this, mLeftGrayTopic, qos); + log_cam_pub(mPubLeftGray); + + mPubRightGray = image_transport::create_publisher(this, mRightGrayTopic, qos); + log_cam_pub(mPubRightGray); + } + if (mPublishImgRaw) { + mPubRawLeft = image_transport::create_publisher(this, mLeftRawTopic, qos); + log_cam_pub(mPubRawLeft); + mPubRawRight = image_transport::create_publisher(this, mRightRawTopic, qos); + log_cam_pub(mPubRawRight); + } + + if (mPublishImgRaw && mPublishImgGray) { + mPubRawLeftGray = image_transport::create_publisher(this, mLeftRawGrayTopic, qos); + log_cam_pub(mPubRawLeftGray); + mPubRawRightGray = image_transport::create_publisher(this, mRightRawGrayTopic, qos); + log_cam_pub(mPubRawRightGray); + } + } + + if (!mDepthDisabled) { + if (mPublishImgRoiMask && (mAutoRoiEnabled || mManualRoiEnabled)) { + mPubRoiMask = image_transport::create_publisher(this, mRoiMaskTopic, qos); + log_cam_pub(mPubRoiMask); + } + if (mPublishDepthMap) { + mPubDepth = image_transport::create_publisher(this, mDepthTopic, qos); + log_cam_pub(mPubDepth); + } + if (mPublishConfidence) { + mPubConfMap = image_transport::create_publisher(this, mConfMapTopic, qos); + log_cam_pub(mPubConfMap); + } + } + + if (mPublishImgStereo) { + mPubStereo = image_transport::create_publisher(this, mStereoTopic, qos); + log_cam_pub(mPubStereo); + + if (mPublishImgRaw) { + mPubRawStereo = image_transport::create_publisher(this, mStereoRawTopic, qos); + log_cam_pub(mPubRawStereo); + } + } + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + // Nitros publishers lambda + auto make_nitros_img_pub = [&](const std::string & topic) { + auto ret = std::make_shared>( + this, topic, nvidia::isaac_ros::nitros::nitros_image_bgra8_t::supported_type_name, + nvidia::isaac_ros::nitros::NitrosDiagnosticsConfig(), mQos); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << topic); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << topic + "/nitros"); + return ret; + }; + + if (mPublishImgRgb) { + mNitrosPubRgb = make_nitros_img_pub(mRgbTopic); + if (mPublishImgGray) { + mNitrosPubRgbGray = make_nitros_img_pub(mRgbGrayTopic); + } + if (mPublishImgRaw) { + mNitrosPubRawRgb = make_nitros_img_pub(mRgbRawTopic); + } + if (mPublishImgGray && mPublishImgRaw) { + mNitrosPubRawRgbGray = make_nitros_img_pub(mRgbRawGrayTopic); + } + } + if (mPublishImgLeftRight) { + mNitrosPubLeft = make_nitros_img_pub(mLeftTopic); + mNitrosPubRight = make_nitros_img_pub(mRightTopic); + if (mPublishImgGray) { + mNitrosPubLeftGray = make_nitros_img_pub(mLeftGrayTopic); + mNitrosPubRightGray = make_nitros_img_pub(mRightGrayTopic); + } + if (mPublishImgRaw) { + mNitrosPubRawLeft = make_nitros_img_pub(mLeftRawTopic); + mNitrosPubRawRight = make_nitros_img_pub(mRightRawTopic); + } + if (mPublishImgGray && mPublishImgRaw) { + mNitrosPubRawLeftGray = make_nitros_img_pub(mLeftRawGrayTopic); + mNitrosPubRawRightGray = make_nitros_img_pub(mRightRawGrayTopic); + } + } + if (mPublishImgRoiMask && (mAutoRoiEnabled || mManualRoiEnabled)) { + mNitrosPubRoiMask = make_nitros_img_pub(mRoiMaskTopic); + } + if (mPublishDepthMap) { + mNitrosPubDepth = std::make_shared>( + this, mDepthTopic, nvidia::isaac_ros::nitros::nitros_image_32FC1_t::supported_type_name, + nvidia::isaac_ros::nitros::NitrosDiagnosticsConfig(), mQos); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << mDepthTopic); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << mDepthTopic + "/nitros"); + } + if (mPublishConfidence) { + mNitrosPubConfMap = make_nitros_img_pub(mConfMapTopic); + } +#endif + } + + // ----> Camera Info publishers + // Lambda to create and log CameraInfo publishers + auto make_cam_info_pub = [&](const std::string & topic) { + std::string info_topic = image_transport::getCameraInfoTopic(topic); + auto pub = create_publisher(info_topic, mQos); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << pub->get_topic_name()); + return pub; + }; + + // Lambda to create and log CameraInfo publishers for image_transport or nitros + auto make_cam_info_trans_pub = [&](const std::string & topic) { + std::string info_topic = topic + "/camera_info"; + auto pub = create_publisher(info_topic, mQos); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << pub->get_topic_name()); + return pub; + }; + + if (mPublishImgRgb) { + mPubRgbCamInfo = make_cam_info_pub(mRgbTopic); + mPubRgbCamInfoTrans = make_cam_info_trans_pub(mRgbTopic); + if (mPublishImgGray) { + mPubRgbGrayCamInfo = make_cam_info_pub(mRgbGrayTopic); + mPubRgbGrayCamInfoTrans = make_cam_info_trans_pub(mRgbGrayTopic); + } + if (mPublishImgRaw) { + mPubRawRgbCamInfo = make_cam_info_pub(mRgbRawTopic); + mPubRawRgbCamInfoTrans = make_cam_info_trans_pub(mRgbRawTopic); + } + if (mPublishImgGray && mPublishImgRaw) { + mPubRawRgbGrayCamInfo = make_cam_info_pub(mRgbRawGrayTopic); + mPubRawRgbGrayCamInfoTrans = make_cam_info_trans_pub(mRgbRawGrayTopic); + } + } + if (mPublishImgLeftRight) { + mPubLeftCamInfo = make_cam_info_pub(mLeftTopic); + mPubLeftCamInfoTrans = make_cam_info_trans_pub(mLeftTopic); + mPubRightCamInfo = make_cam_info_pub(mRightTopic); + mPubRightCamInfoTrans = make_cam_info_trans_pub(mRightTopic); + if (mPublishImgGray) { + mPubLeftGrayCamInfo = make_cam_info_pub(mLeftGrayTopic); + mPubLeftGrayCamInfoTrans = make_cam_info_trans_pub(mLeftGrayTopic); + mPubRightGrayCamInfo = make_cam_info_pub(mRightGrayTopic); + mPubRightGrayCamInfoTrans = make_cam_info_trans_pub(mRightGrayTopic); + } + if (mPublishImgRaw) { + mPubRawLeftCamInfo = make_cam_info_pub(mLeftRawTopic); + mPubRawLeftCamInfoTrans = make_cam_info_trans_pub(mLeftRawTopic); + mPubRawRightCamInfo = make_cam_info_pub(mRightRawTopic); + mPubRawRightCamInfoTrans = make_cam_info_trans_pub(mRightRawTopic); + } + if (mPublishImgGray && mPublishImgRaw) { + mPubRawLeftGrayCamInfo = make_cam_info_pub(mLeftRawGrayTopic); + mPubRawLeftGrayCamInfoTrans = make_cam_info_trans_pub(mLeftRawGrayTopic); + mPubRawRightGrayCamInfo = make_cam_info_pub(mRightRawGrayTopic); + mPubRawRightGrayCamInfoTrans = make_cam_info_trans_pub(mRightRawGrayTopic); + } + } + if (mPublishImgRoiMask && (mAutoRoiEnabled || mManualRoiEnabled)) { + mPubRoiMaskCamInfo = make_cam_info_pub(mRoiMaskTopic); + mPubRoiMaskCamInfoTrans = make_cam_info_trans_pub(mRoiMaskTopic); + } + if (mPublishDepthMap) { + mPubDepthCamInfo = make_cam_info_pub(mDepthTopic); + mPubDepthCamInfoTrans = make_cam_info_trans_pub(mDepthTopic); + } + if (mPublishConfidence) { + mPubConfMapCamInfo = make_cam_info_pub(mConfMapTopic); + mPubConfMapCamInfoTrans = make_cam_info_trans_pub(mConfMapTopic); + } + // <---- Camera Info publishers + + // ----> Other depth-related publishers + if (!mDepthDisabled) { + if (mPublishDepthInfo) { + mPubDepthInfo = create_publisher( + mDepthInfoTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubDepthInfo->get_topic_name()); + } + + // Point cloud and disparity publishers + if (mPublishDisparity) { + mPubDisparity = create_publisher( + mDisparityTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << mPubDisparity->get_topic_name()); + } + + if (mPublishPointcloud) { +#ifdef FOUND_POINT_CLOUD_TRANSPORT + mPubCloud = point_cloud_transport::create_publisher( + shared_from_this(), mPointcloudTopic, qos, mPubOpt); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << mPubCloud.getTopic()); +#else + mPubCloud = create_publisher(mPointcloudTopic, mQos, mPubOpt); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << mPubCloud->get_topic_name()); +#endif + } + } + // <---- Other depth-related publishers +} + +void ZedCamera::getVideoParams() +{ + rclcpp::Parameter paramVal; + + RCLCPP_INFO(get_logger(), "=== VIDEO parameters ==="); + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + if (!sl_tools::isZEDX(mCamUserModel)) { + sl_tools::getParam( + shared_from_this(), "video.brightness", mCamBrightness, + mCamBrightness, " * Brightness: ", true, 0, 8); + sl_tools::getParam( + shared_from_this(), "video.contrast", mCamContrast, + mCamContrast, " * Contrast: ", true, 0, 8); + sl_tools::getParam( + shared_from_this(), "video.hue", mCamHue, mCamHue, + " * Hue: ", true, 0, 11); + } + + sl_tools::getParam( + shared_from_this(), "video.saturation", mCamSaturation, + mCamSaturation, " * Saturation: ", true, 0, 8); + sl_tools::getParam( + shared_from_this(), "video.sharpness", mCamSharpness, + mCamSharpness, " * Sharpness: ", true, 0, 8); + sl_tools::getParam( + shared_from_this(), "video.gamma", mCamGamma, mCamGamma, + " * Gamma: ", true, 1, 9); + sl_tools::getParam( + shared_from_this(), "video.auto_exposure_gain", + mCamAutoExpGain, mCamAutoExpGain, + " * Auto Exposure/Gain: ", true); + if (mCamAutoExpGain) { + mTriggerAutoExpGain = true; + } + sl_tools::getParam( + shared_from_this(), "video.exposure", mCamExposure, + mCamExposure, " * Exposure: ", true, 0, 100); + sl_tools::getParam( + shared_from_this(), "video.gain", mCamGain, mCamGain, + " * Gain: ", true, 0, 100); + sl_tools::getParam( + shared_from_this(), "video.auto_whitebalance", mCamAutoWB, + mCamAutoWB, " * Auto White Balance: ", true); + if (mCamAutoWB) { + mTriggerAutoWB = true; + } + int wb = 42; + sl_tools::getParam( + shared_from_this(), "video.whitebalance_temperature", wb, + wb, " * White Balance Temperature: ", true, 28, 65); + mCamWBTemp = wb * 100; + + if (sl_tools::isZEDX(mCamUserModel)) { + sl_tools::getParam( + shared_from_this(), "video.exposure_time", mGmslExpTime, + mGmslExpTime, " * ZED X Exposure time: ", true, 28, + 66000); + sl_tools::getParam( + shared_from_this(), "video.auto_exposure_time_range_min", + mGmslAutoExpTimeRangeMin, mGmslAutoExpTimeRangeMin, + " * ZED X Auto Exp. time range min: ", true, 28, 66000); + sl_tools::getParam( + shared_from_this(), "video.auto_exposure_time_range_max", + mGmslAutoExpTimeRangeMax, mGmslAutoExpTimeRangeMax, + " * ZED X Auto Exp. time range max: ", true, 28, 66000); + sl_tools::getParam( + shared_from_this(), "video.exposure_compensation", + mGmslExposureComp, mGmslExposureComp, + " * ZED X Exposure comp.: ", true, 0, 100); + sl_tools::getParam( + shared_from_this(), "video.analog_gain", mGmslAnalogGain, + mGmslAnalogGain, " * ZED X Analog Gain: ", true, 1000, + 16000); + sl_tools::getParam( + shared_from_this(), "video.auto_analog_gain_range_min", + mGmslAnalogGainRangeMin, mGmslAnalogGainRangeMin, + " * ZED X Auto Analog Gain range min: ", true, 1000, + 16000); + sl_tools::getParam( + shared_from_this(), "video.auto_analog_gain_range_max", + mGmslAnalogGainRangeMax, mGmslAnalogGainRangeMax, + " * ZED X Auto Analog Gain range max: ", true, 1000, + 16000); + sl_tools::getParam( + shared_from_this(), "video.digital_gain", + mGmslDigitalGain, mGmslDigitalGain, + " * ZED X Digital Gain: ", true, 1, 256); + sl_tools::getParam( + shared_from_this(), "video.auto_digital_gain_range_min", + mGmslAutoDigitalGainRangeMin, + mGmslAutoDigitalGainRangeMin, + " * ZED X Auto Digital Gain range min: ", true, 1, 256); + sl_tools::getParam( + shared_from_this(), "video.auto_digital_gain_range_max", + mGmslAutoDigitalGainRangeMax, + mGmslAutoDigitalGainRangeMax, + " * ZED X Auto Digital Gain range max: ", true, 1, 256); + sl_tools::getParam( + shared_from_this(), "video.denoising", mGmslDenoising, + mGmslDenoising, + " * ZED X Auto Digital Gain range max: ", true, 0, 100); + } +} + +void ZedCamera::getDepthParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== DEPTH parameters ==="); + + std::string depth_mode_str = sl::toString(mDepthMode).c_str(); + sl_tools::getParam( + shared_from_this(), "depth.depth_mode", depth_mode_str, + depth_mode_str); + + // Check for model override syntax: e.g. 'NEURAL_LIGHT:neural_depth_light_5.3.model' + // Supported separators: ':', ',', ';' + mDepthModelOverride.clear(); + for (char sep : {':', ',', ';'}) { + auto pos = depth_mode_str.find(sep); + if (pos != std::string::npos) { + mDepthModelOverride = depth_mode_str.substr(pos + 1); + depth_mode_str = depth_mode_str.substr(0, pos); + break; + } + } + + if (!sl_tools::matchSdkEnum( + depth_mode_str, sl::DEPTH_MODE::NONE, + sl::DEPTH_MODE::LAST, mDepthMode)) + { + mDepthMode = sl::DEPTH_MODE::NEURAL; + if (sl_tools::toUpper(depth_mode_str) != "NEURAL_LIGHT") { + RCLCPP_WARN( + get_logger(), + "The parameter 'depth.depth_mode' contains a not valid string. " + "Please check it in 'common_stereo.yaml'."); + RCLCPP_WARN_STREAM(get_logger(), "Using default value: " << sl::toString(mDepthMode).c_str()); + } + } + + if (!mDepthModelOverride.empty()) { + RCLCPP_INFO_STREAM( + get_logger(), + " * Depth model override: " << mDepthModelOverride); + } + + if (mDepthMode == sl::DEPTH_MODE::NONE) { + mDepthDisabled = true; + mDepthStabilization = 0; + RCLCPP_INFO_STREAM( + get_logger(), + " * Depth mode: " << sl::toString(mDepthMode).c_str() + << " - DEPTH DISABLED"); + } else { + mDepthDisabled = false; + RCLCPP_INFO_STREAM( + get_logger(), + " * Depth mode: " << sl::toString(mDepthMode).c_str() + << " [" << static_cast(mDepthMode) + << "]"); + } + + if (!mDepthDisabled) { +#if ((ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51) + const double default_min_depth = 0.1; +#else + const double default_min_depth = 0.01; +#endif + sl_tools::getParam( + shared_from_this(), "depth.min_depth", mCamMinDepth, + mCamMinDepth, " * Min depth [m]: ", false, + default_min_depth, 3.0); + sl_tools::getParam( + shared_from_this(), "depth.max_depth", mCamMaxDepth, + mCamMaxDepth, " * Max depth [m]: ", false, 0.5, 1000.0); + + sl_tools::getParam( + shared_from_this(), "depth.depth_stabilization", + mDepthStabilization, mDepthStabilization, + " * Depth Stabilization: ", false, -1, 100); + // -1 means use SDK default (mInitParams keeps its constructed default value) + + if (_nitrosDisabled) { + sl_tools::getParam( + shared_from_this(), "depth.openni_depth_mode", + mOpenniDepthMode, mOpenniDepthMode, + " * OpenNI mode (16bit depth): "); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + RCLCPP_INFO(get_logger(), " * OpenNI mode (16bit depth): DISABLED with NITROS"); +#endif + } + + sl_tools::getParam( + shared_from_this(), "depth.point_cloud_freq", mPcPubRate, + mPcPubRate, "", true, -1.0, static_cast(mCamGrabFrameRate)); + if (mPcPubRate <= 0.0) { + mPcPubRate = static_cast(mCamGrabFrameRate); + } + RCLCPP_INFO_STREAM( + get_logger(), + " * Point cloud rate [Hz]: " << mPcPubRate); + + std::string out_resol = "COMPACT"; + sl_tools::getParam( + shared_from_this(), "depth.point_cloud_res", out_resol, + out_resol); + if (out_resol == toString(PcRes::PUB)) { + mPcResolution = PcRes::PUB; + } else if (out_resol == toString(PcRes::FULL)) { + mPcResolution = PcRes::FULL; + } else if (out_resol == toString(PcRes::COMPACT)) { + mPcResolution = PcRes::COMPACT; + } else if (out_resol == toString(PcRes::REDUCED)) { + mPcResolution = PcRes::REDUCED; + } else { + RCLCPP_WARN( + get_logger(), + "Not valid 'depth.point_cloud_res' value: '%s'. Using default " + "setting instead.", + out_resol.c_str()); + out_resol = "COMPACT -> Fix the value in YAML!"; + mPcResolution = PcRes::COMPACT; + } + RCLCPP_INFO_STREAM( + get_logger(), + " * Point cloud resolution: " << out_resol.c_str()); + + sl_tools::getParam( + shared_from_this(), "depth.depth_confidence", mDepthConf, + mDepthConf, " * Depth Confidence: ", true, 0, 100); + sl_tools::getParam( + shared_from_this(), "depth.depth_texture_conf", + mDepthTextConf, mDepthTextConf, + " * Depth Texture Confidence: ", true, 0, 100); + sl_tools::getParam( + shared_from_this(), "depth.remove_saturated_areas", + mRemoveSatAreas, mRemoveSatAreas, + " * Remove saturated areas: ", true); + // ------------------------------------------ + } +} + +void ZedCamera::fillCamInfo( + const std::shared_ptr & zed, + const sensor_msgs::msg::CameraInfo::SharedPtr & leftCamInfoMsg, + const sensor_msgs::msg::CameraInfo::SharedPtr & rightCamInfoMsg, + const std::string & leftFrameId, const std::string & rightFrameId, + bool rawParam /*= false*/) +{ + sl::CalibrationParameters zedParam; + + if (rawParam) { + zedParam = zed->getCameraInformation(mMatResol) + .camera_configuration.calibration_parameters_raw; + } else { + zedParam = zed->getCameraInformation(mMatResol) + .camera_configuration.calibration_parameters; + } + + float baseline = zedParam.getCameraBaseline(); + + // ----> Distortion models + // ZED SDK params order: [ k1, k2, p1, p2, k3, k4, k5, k6, s1, s2, s3, s4] + // Radial (k1, k2, k3, k4, k5, k6), Tangential (p1,p2) and Prism (s1, s2, s3, + // s4) distortion. Prism not currently used. + + // ROS2 order (OpenCV) -> k1,k2,p1,p2,k3,k4,k5,k6,s1,s2,s3,s4 + switch (mCamRealModel) { + case sl::MODEL::ZED: // PLUMB_BOB + leftCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::PLUMB_BOB; + rightCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::PLUMB_BOB; + leftCamInfoMsg->d.resize(5); + rightCamInfoMsg->d.resize(5); + leftCamInfoMsg->d[0] = zedParam.left_cam.disto[0]; // k1 + leftCamInfoMsg->d[1] = zedParam.left_cam.disto[1]; // k2 + leftCamInfoMsg->d[2] = zedParam.left_cam.disto[2]; // p1 + leftCamInfoMsg->d[3] = zedParam.left_cam.disto[3]; // p2 + leftCamInfoMsg->d[4] = zedParam.left_cam.disto[4]; // k3 + rightCamInfoMsg->d[0] = zedParam.right_cam.disto[0]; // k1 + rightCamInfoMsg->d[1] = zedParam.right_cam.disto[1]; // k2 + rightCamInfoMsg->d[2] = zedParam.right_cam.disto[2]; // p1 + rightCamInfoMsg->d[3] = zedParam.right_cam.disto[3]; // p2 + rightCamInfoMsg->d[4] = zedParam.right_cam.disto[4]; // k3 + break; + + case sl::MODEL::ZED2: // RATIONAL_POLYNOMIAL + case sl::MODEL::ZED2i: // RATIONAL_POLYNOMIAL + case sl::MODEL::ZED_X: // RATIONAL_POLYNOMIAL + case sl::MODEL::ZED_XM: // RATIONAL_POLYNOMIAL + case sl::MODEL::VIRTUAL_ZED_X: // RATIONAL_POLYNOMIAL + leftCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::RATIONAL_POLYNOMIAL; + rightCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::RATIONAL_POLYNOMIAL; + leftCamInfoMsg->d.resize(8); + rightCamInfoMsg->d.resize(8); + leftCamInfoMsg->d[0] = zedParam.left_cam.disto[0]; // k1 + leftCamInfoMsg->d[1] = zedParam.left_cam.disto[1]; // k2 + leftCamInfoMsg->d[2] = zedParam.left_cam.disto[2]; // p1 + leftCamInfoMsg->d[3] = zedParam.left_cam.disto[3]; // p2 + leftCamInfoMsg->d[4] = zedParam.left_cam.disto[4]; // k3 + leftCamInfoMsg->d[5] = zedParam.left_cam.disto[5]; // k4 + leftCamInfoMsg->d[6] = zedParam.left_cam.disto[6]; // k5 + leftCamInfoMsg->d[7] = zedParam.left_cam.disto[7]; // k6 + rightCamInfoMsg->d[0] = zedParam.right_cam.disto[0]; // k1 + rightCamInfoMsg->d[1] = zedParam.right_cam.disto[1]; // k2 + rightCamInfoMsg->d[2] = zedParam.right_cam.disto[2]; // p1 + rightCamInfoMsg->d[3] = zedParam.right_cam.disto[3]; // p2 + rightCamInfoMsg->d[4] = zedParam.right_cam.disto[4]; // k3 + rightCamInfoMsg->d[5] = zedParam.right_cam.disto[5]; // k4 + rightCamInfoMsg->d[6] = zedParam.right_cam.disto[6]; // k5 + rightCamInfoMsg->d[7] = zedParam.right_cam.disto[7]; // k6 + break; + + case sl::MODEL::ZED_M: + if (zedParam.left_cam.disto[5] != 0 && // k4!=0 + zedParam.right_cam.disto[2] == 0 && // p1==0 + zedParam.right_cam.disto[3] == 0) // p2==0 + { + leftCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::EQUIDISTANT; + rightCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::EQUIDISTANT; + + leftCamInfoMsg->d.resize(4); + rightCamInfoMsg->d.resize(4); + leftCamInfoMsg->d[0] = zedParam.left_cam.disto[0]; // k1 + leftCamInfoMsg->d[1] = zedParam.left_cam.disto[1]; // k2 + leftCamInfoMsg->d[2] = zedParam.left_cam.disto[4]; // k3 + leftCamInfoMsg->d[3] = zedParam.left_cam.disto[5]; // k4 + rightCamInfoMsg->d[0] = zedParam.right_cam.disto[0]; // k1 + rightCamInfoMsg->d[1] = zedParam.right_cam.disto[1]; // k2 + rightCamInfoMsg->d[2] = zedParam.right_cam.disto[4]; // k3 + rightCamInfoMsg->d[3] = zedParam.right_cam.disto[5]; // k4 + } else { + leftCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::PLUMB_BOB; + rightCamInfoMsg->distortion_model = + sensor_msgs::distortion_models::PLUMB_BOB; + leftCamInfoMsg->d.resize(5); + rightCamInfoMsg->d.resize(5); + leftCamInfoMsg->d[0] = zedParam.left_cam.disto[0]; // k1 + leftCamInfoMsg->d[1] = zedParam.left_cam.disto[1]; // k2 + leftCamInfoMsg->d[2] = zedParam.left_cam.disto[2]; // p1 + leftCamInfoMsg->d[3] = zedParam.left_cam.disto[3]; // p2 + leftCamInfoMsg->d[4] = zedParam.left_cam.disto[4]; // k3 + rightCamInfoMsg->d[0] = zedParam.right_cam.disto[0]; // k1 + rightCamInfoMsg->d[1] = zedParam.right_cam.disto[1]; // k2 + rightCamInfoMsg->d[2] = zedParam.right_cam.disto[2]; // p1 + rightCamInfoMsg->d[3] = zedParam.right_cam.disto[3]; // p2 + rightCamInfoMsg->d[4] = zedParam.right_cam.disto[4]; // k3 + } + } + + leftCamInfoMsg->k.fill(0.0); + rightCamInfoMsg->k.fill(0.0); + leftCamInfoMsg->k[0] = static_cast(zedParam.left_cam.fx); + leftCamInfoMsg->k[2] = static_cast(zedParam.left_cam.cx); + leftCamInfoMsg->k[4] = static_cast(zedParam.left_cam.fy); + leftCamInfoMsg->k[5] = static_cast(zedParam.left_cam.cy); + leftCamInfoMsg->k[8] = 1.0; + rightCamInfoMsg->k[0] = static_cast(zedParam.right_cam.fx); + rightCamInfoMsg->k[2] = static_cast(zedParam.right_cam.cx); + rightCamInfoMsg->k[4] = static_cast(zedParam.right_cam.fy); + rightCamInfoMsg->k[5] = static_cast(zedParam.right_cam.cy); + rightCamInfoMsg->k[8] = 1.0; + leftCamInfoMsg->r.fill(0.0); + rightCamInfoMsg->r.fill(0.0); + + for (size_t i = 0; i < 3; i++) { + // identity + rightCamInfoMsg->r[i + i * 3] = 1; + leftCamInfoMsg->r[i + i * 3] = 1; + } + + if (rawParam) { + // ROS frame (X forward, Z up, Y left) + for (int i = 0; i < 9; i++) { + rightCamInfoMsg->r[i] = + zedParam.stereo_transform.getRotationMatrix().r[i]; + } + } + + leftCamInfoMsg->p.fill(0.0); + rightCamInfoMsg->p.fill(0.0); + leftCamInfoMsg->p[0] = static_cast(zedParam.left_cam.fx); + leftCamInfoMsg->p[2] = static_cast(zedParam.left_cam.cx); + leftCamInfoMsg->p[5] = static_cast(zedParam.left_cam.fy); + leftCamInfoMsg->p[6] = static_cast(zedParam.left_cam.cy); + leftCamInfoMsg->p[10] = 1.0; + // http://docs.ros.org/api/sensor_msgs/html/msg/CameraInfo.html + rightCamInfoMsg->p[3] = + static_cast(-1 * zedParam.left_cam.fx * baseline); + rightCamInfoMsg->p[0] = static_cast(zedParam.right_cam.fx); + rightCamInfoMsg->p[2] = static_cast(zedParam.right_cam.cx); + rightCamInfoMsg->p[5] = static_cast(zedParam.right_cam.fy); + rightCamInfoMsg->p[6] = static_cast(zedParam.right_cam.cy); + rightCamInfoMsg->p[10] = 1.0; + leftCamInfoMsg->width = rightCamInfoMsg->width = + static_cast(mMatResol.width); + leftCamInfoMsg->height = rightCamInfoMsg->height = + static_cast(mMatResol.height); + leftCamInfoMsg->header.frame_id = leftFrameId; + rightCamInfoMsg->header.frame_id = rightFrameId; +} + +bool ZedCamera::areVideoDepthSubscribed() +{ + if (!updateVideoDepthSubscribers()) { + return false; + } + + return ( + mRgbSubCount + mRgbRawSubCount + mRgbGraySubCount + mRgbGrayRawSubCount + + mLeftSubCount + mLeftRawSubCount + mLeftGraySubCount + mLeftGrayRawSubCount + + mRightSubCount + mRightRawSubCount + mRightGraySubCount + mRightGrayRawSubCount + + mStereoSubCount + mStereoRawSubCount + + mDepthSubCount + mConfMapSubCount + mDisparitySubCount + mDepthInfoSubCount + ) > 0; +} + +bool ZedCamera::updateVideoDepthSubscribers(bool force) +{ + constexpr auto kSubQueryInterval = std::chrono::milliseconds(200); + auto now = std::chrono::steady_clock::now(); + + if (!force && mVideoDepthSubCountInit && + (now - mLastVideoDepthSubCountQuery) < kSubQueryInterval) + { + return true; + } + + mLastVideoDepthSubCountQuery = now; + mVideoDepthSubCountInit = true; + + mRgbSubCount = 0; + mRgbRawSubCount = 0; + mRgbGraySubCount = 0; + mRgbGrayRawSubCount = 0; + mLeftSubCount = 0; + mLeftRawSubCount = 0; + mLeftGraySubCount = 0; + mLeftGrayRawSubCount = 0; + mRightSubCount = 0; + mRightRawSubCount = 0; + mRightGraySubCount = 0; + mRightGrayRawSubCount = 0; + mStereoSubCount = 0; + mStereoRawSubCount = 0; + mDepthSubCount = 0; + mConfMapSubCount = 0; + mDisparitySubCount = 0; + mDepthInfoSubCount = 0; + mPcSubCount = 0; + + try { + if (_nitrosDisabled) { + if (mPublishImgRgb) { + mRgbSubCount = mPubRgb.getNumSubscribers(); + if (mPublishImgRaw) { + mRgbRawSubCount = mPubRawRgb.getNumSubscribers(); + } + if (mPublishImgGray) { + mRgbGraySubCount = mPubRgbGray.getNumSubscribers(); + if (mPublishImgRaw) { + mRgbGrayRawSubCount = mPubRawRgbGray.getNumSubscribers(); + } + } + } + if (mPublishImgLeftRight) { + mLeftSubCount = mPubLeft.getNumSubscribers(); + mRightSubCount = mPubRight.getNumSubscribers(); + if (mPublishImgRaw) { + mLeftRawSubCount = mPubRawLeft.getNumSubscribers(); + mRightRawSubCount = mPubRawRight.getNumSubscribers(); + } + if (mPublishImgGray) { + mLeftGraySubCount = mPubLeftGray.getNumSubscribers(); + mRightGraySubCount = mPubRightGray.getNumSubscribers(); + if (mPublishImgRaw) { + mLeftGrayRawSubCount = mPubRawLeftGray.getNumSubscribers(); + mRightGrayRawSubCount = mPubRawRightGray.getNumSubscribers(); + } + } + } + if (mPublishImgStereo) { + mStereoSubCount = mPubStereo.getNumSubscribers(); + mStereoRawSubCount = mPubRawStereo.getNumSubscribers(); + } + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + mRgbSubCount = count_subscribers(mRgbTopic) + count_subscribers(mRgbTopic + "/nitros"); + mRgbRawSubCount = count_subscribers(mRgbRawTopic) + count_subscribers( + mRgbRawTopic + "/nitros"); + mRgbGraySubCount = count_subscribers(mRgbGrayTopic) + count_subscribers( + mRgbGrayTopic + "/nitros"); + mRgbGrayRawSubCount = count_subscribers(mRgbRawGrayTopic) + count_subscribers( + mRgbRawGrayTopic + "/nitros"); + mLeftSubCount = count_subscribers(mLeftTopic) + count_subscribers(mLeftTopic + "/nitros"); + mLeftRawSubCount = count_subscribers(mLeftRawTopic) + count_subscribers( + mLeftRawTopic + "/nitros"); + mLeftGraySubCount = count_subscribers(mLeftGrayTopic) + count_subscribers( + mLeftGrayTopic + "/nitros"); + mLeftGrayRawSubCount = count_subscribers(mLeftRawGrayTopic) + count_subscribers( + mLeftRawGrayTopic + "/nitros"); + mRightSubCount = count_subscribers(mRightTopic) + count_subscribers( + mRightTopic + "/nitros"); + mRightRawSubCount = count_subscribers(mRightRawTopic) + count_subscribers( + mRightRawTopic + "/nitros"); + mRightGraySubCount = count_subscribers(mRightGrayTopic) + count_subscribers( + mRightGrayTopic + "/nitros"); + mRightGrayRawSubCount = count_subscribers(mRightRawGrayTopic) + count_subscribers( + mRightRawGrayTopic + "/nitros"); + mStereoSubCount = count_subscribers(mStereoTopic) + count_subscribers( + mStereoTopic + "/nitros"); + mStereoRawSubCount = count_subscribers(mStereoRawTopic) + count_subscribers( + mStereoRawTopic + "/nitros"); +#endif + } + + + if (!mDepthDisabled) { + if (_nitrosDisabled) { + if (mPublishDepthMap) { + mDepthSubCount = mPubDepth.getNumSubscribers(); + } + if (mPublishConfidence) { + mConfMapSubCount = mPubConfMap.getNumSubscribers(); + } + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + mDepthSubCount = count_subscribers(mDepthTopic) + count_subscribers( + mDepthTopic + "/nitros"); + mConfMapSubCount = count_subscribers(mConfMapTopic) + count_subscribers( + mConfMapTopic + "/nitros"); +#endif + } + if (mPubDepthInfo) { + mDepthInfoSubCount = count_subscribers(mPubDepthInfo->get_topic_name()); + } + if (mPubDisparity) { + mDisparitySubCount = count_subscribers(mPubDisparity->get_topic_name()); + } + +#ifdef FOUND_POINT_CLOUD_TRANSPORT + mPcSubCount = mPubCloud.getNumSubscribers(); +#else + if (mPubCloud) { + mPcSubCount = count_subscribers(mPubCloud->get_topic_name()); + } +#endif + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_VD(" * [updateVideoDepthSubscribers] Exception while counting subscribers"); + return false; + } + + return true; +} + +bool ZedCamera::isDepthRequired() +{ + // DEBUG_STREAM_COMM( "isDepthRequired called"); + + if (mDepthDisabled) { + DEBUG_STREAM_COMM("Depth not required: depth disabled"); + return false; + } + + if (!updateVideoDepthSubscribers()) { + DEBUG_STREAM_VD(" * [isDepthRequired] failed to refresh subscribers, using cached values"); + } + + size_t tot_sub = + mDepthSubCount + mConfMapSubCount + mDisparitySubCount + mPcSubCount + + mDepthInfoSubCount; + + bool pos_tracking_required = isPosTrackingRequired(); + bool depth_required_for_pos_trk = pos_tracking_required; + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 52 + // With ZED SDK v5.2 we can use Positional Tracking `GEN_3` even if depth is + // disabled + depth_required_for_pos_trk = pos_tracking_required && + (mPosTrkMode != sl::POSITIONAL_TRACKING_MODE::GEN_3); +#endif + + return tot_sub > 0 || depth_required_for_pos_trk; +} + +void ZedCamera::applyDepthSettings() +{ + if (isDepthRequired()) { + std::lock_guard lock(mDynParMutex); + mRunParams.confidence_threshold = + mDepthConf; // Update depth confidence if changed + mRunParams.texture_confidence_threshold = + mDepthTextConf; // Update depth texture confidence if changed + mRunParams.remove_saturated_areas = mRemoveSatAreas; + + DEBUG_STREAM_COMM("Depth processing enabled"); + mRunParams.enable_depth = true; + + } else { + DEBUG_STREAM_COMM("Depth processing disabled"); + mRunParams.enable_depth = false; + } +} + +void ZedCamera::applyVideoSettings() +{ + if (!mSvoMode && mCamSettingsDirty && mFrameCount % 10 == 0) { + std::lock_guard lock(mDynParMutex); + + applyAutoExposureGainSettings(); + applyExposureGainSettings(); + applyWhiteBalanceSettings(); + applyBrightnessContrastHueSettings(); + applySaturationSharpnessGammaSettings(); + applyZEDXSettings(); + + mCamSettingsDirty = false; + } +} + +// Helper: Auto Exposure/Gain +void ZedCamera::applyAutoExposureGainSettings() +{ + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting; + + if (mTriggerAutoExpGain) { + setting = sl::VIDEO_SETTINGS::AEC_AGC; + err = mZed->setCameraSettings(setting, (mCamAutoExpGain ? 1 : 0)); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting AEC_AGC: " + << sl::toString(err).c_str()); + } else { + mTriggerAutoExpGain = false; + DEBUG_STREAM_CTRL( + "New setting for " << sl::toString(setting).c_str() + << ": " + << (mCamAutoExpGain ? 1 : 0)); + } + } +} + +// Helper: Exposure and Gain +void ZedCamera::applyExposureGainSettings() +{ + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting; + + if (!mCamAutoExpGain) { + int value; + err = mZed->getCameraSettings(sl::VIDEO_SETTINGS::EXPOSURE, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamExposure) { + mZed->setCameraSettings(sl::VIDEO_SETTINGS::EXPOSURE, mCamExposure); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " + << sl::toString(sl::VIDEO_SETTINGS::EXPOSURE).c_str() << ": " + << sl::toString(err).c_str()); + } + + err = mZed->getCameraSettings(sl::VIDEO_SETTINGS::GAIN, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamGain) { + err = mZed->setCameraSettings(sl::VIDEO_SETTINGS::GAIN, mCamGain); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " + << sl::toString(sl::VIDEO_SETTINGS::GAIN).c_str() + << ": " << sl::toString(err).c_str()); + } + } +} + +// Helper: White Balance +void ZedCamera::applyWhiteBalanceSettings() +{ + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting; + + if (mTriggerAutoWB) { + setting = sl::VIDEO_SETTINGS::WHITEBALANCE_AUTO; + err = mZed->setCameraSettings(setting, (mCamAutoWB ? 1 : 0)); + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } else { + mTriggerAutoWB = false; + DEBUG_STREAM_CTRL( + "New setting for " << sl::toString(setting).c_str() + << ": " << (mCamAutoWB ? 1 : 0)); + } + } + + if (!mCamAutoWB) { + int value; + setting = sl::VIDEO_SETTINGS::WHITEBALANCE_TEMPERATURE; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamWBTemp) { + err = mZed->setCameraSettings(setting, mCamWBTemp); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + } +} + +// Helper: Brightness, Contrast, Hue (not for ZED X) +void ZedCamera::applyBrightnessContrastHueSettings() +{ + if (!sl_tools::isZEDX(mCamRealModel)) { + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting; + int value; + + setting = sl::VIDEO_SETTINGS::BRIGHTNESS; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamBrightness) { + mZed->setCameraSettings(setting, mCamBrightness); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + + setting = sl::VIDEO_SETTINGS::CONTRAST; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamContrast) { + err = mZed->setCameraSettings(setting, mCamContrast); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + + setting = sl::VIDEO_SETTINGS::HUE; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamHue) { + mZed->setCameraSettings(setting, mCamHue); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + } +} + +// Helper: Saturation, Sharpness, Gamma +void ZedCamera::applySaturationSharpnessGammaSettings() +{ + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting; + int value; + + setting = sl::VIDEO_SETTINGS::SATURATION; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamSaturation) { + mZed->setCameraSettings(setting, mCamSaturation); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " << sl::toString(setting).c_str() + << ": " << sl::toString(err).c_str()); + } + + setting = sl::VIDEO_SETTINGS::SHARPNESS; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamSharpness) { + mZed->setCameraSettings(setting, mCamSharpness); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " << sl::toString(setting).c_str() + << ": " << sl::toString(err).c_str()); + } + + setting = sl::VIDEO_SETTINGS::GAMMA; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mCamGamma) { + err = mZed->setCameraSettings(setting, mCamGamma); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " << sl::toString(setting).c_str() + << ": " << sl::toString(err).c_str()); + } +} + +// Helper: ZED X specific settings +void ZedCamera::applyZEDXSettings() +{ + if (!sl_tools::isZEDX(mCamRealModel)) { + return; + } + + applyZEDXExposureSettings(); + applyZEDXAutoExposureTimeRange(); + applyZEDXExposureCompensation(); + applyZEDXAnalogDigitalGain(); + applyZEDXAutoAnalogGainRange(); + applyZEDXAutoDigitalGainRange(); + applyZEDXDenoising(); +} + +void ZedCamera::applyZEDXExposureSettings() +{ + if (!mCamAutoExpGain) { + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting = sl::VIDEO_SETTINGS::EXPOSURE_TIME; + int value; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mGmslExpTime) { + err = mZed->setCameraSettings(setting, mGmslExpTime); + DEBUG_STREAM_CTRL( + "New setting for " << sl::toString(setting).c_str() + << ": " << mGmslExpTime << " [Old " + << value << "]"); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + } +} + +void ZedCamera::applyZEDXAutoExposureTimeRange() +{ + // ----> TODO(Walter) Remove this check when fixed in ZED SDK + if (mCamRealModel == sl::MODEL::VIRTUAL_ZED_X) { + DEBUG_VD( + "Auto Digital Gain Range not supported for VIRTUAL_ZED_X model. " + "Skipping setting."); + return; + } + // <---- TODO(Walter) Remove this check when fixed in ZED SDK + + sl::ERROR_CODE err; + int value_min, value_max; + err = mZed->getCameraSettings( + sl::VIDEO_SETTINGS::AUTO_EXPOSURE_TIME_RANGE, + value_min, value_max); + if (err == sl::ERROR_CODE::SUCCESS && + (value_min != mGmslAutoExpTimeRangeMin || + value_max != mGmslAutoExpTimeRangeMax)) + { + err = mZed->setCameraSettings( + sl::VIDEO_SETTINGS::AUTO_EXPOSURE_TIME_RANGE, + mGmslAutoExpTimeRangeMin, mGmslAutoExpTimeRangeMax); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString( + sl::VIDEO_SETTINGS::AUTO_EXPOSURE_TIME_RANGE) + .c_str() + << ": " << sl::toString(err).c_str()); + } +} + +void ZedCamera::applyZEDXExposureCompensation() +{ + if (!mStreamMode) { + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting = sl::VIDEO_SETTINGS::EXPOSURE_COMPENSATION; + int value; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mGmslExposureComp) { + err = mZed->setCameraSettings(setting, mGmslExposureComp); + DEBUG_STREAM_CTRL( + "New setting for " << sl::toString(setting).c_str() + << ": " << mGmslExposureComp + << " [Old " << value << "]"); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + } +} + +void ZedCamera::applyZEDXAnalogDigitalGain() +{ + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting = sl::VIDEO_SETTINGS::ANALOG_GAIN; + + if (!mCamAutoExpGain) { + int value; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mGmslAnalogGain) { + err = mZed->setCameraSettings(setting, mGmslAnalogGain); + DEBUG_STREAM_CTRL( + "New setting for " << sl::toString(setting).c_str() + << ": " << mGmslAnalogGain + << " [Old " << value << "]"); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + + setting = sl::VIDEO_SETTINGS::DIGITAL_GAIN; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mGmslDigitalGain) { + err = mZed->setCameraSettings(setting, mGmslDigitalGain); + DEBUG_STREAM_CTRL( + "New setting for " << sl::toString(setting).c_str() + << ": " << mGmslDigitalGain + << " [Old " << value << "]"); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + } +} + +void ZedCamera::applyZEDXAutoAnalogGainRange() +{ + // ----> TODO(Walter) Remove this check when fixed in ZED SDK + if (mCamRealModel == sl::MODEL::VIRTUAL_ZED_X) { + DEBUG_VD( + "Auto Analog Gain Range not supported for VIRTUAL_ZED_X model. " + "Skipping setting."); + return; + } + // <---- TODO(Walter) Remove this check when fixed in ZED SDK + + sl::ERROR_CODE err; + int value_min, value_max; + err = mZed->getCameraSettings( + sl::VIDEO_SETTINGS::AUTO_ANALOG_GAIN_RANGE, + value_min, value_max); + if (err == sl::ERROR_CODE::SUCCESS && + (value_min != mGmslAnalogGainRangeMin || + value_max != mGmslAnalogGainRangeMax)) + { + err = mZed->setCameraSettings( + sl::VIDEO_SETTINGS::AUTO_ANALOG_GAIN_RANGE, + mGmslAnalogGainRangeMin, + mGmslAnalogGainRangeMax); + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " + << sl::toString(sl::VIDEO_SETTINGS::AUTO_ANALOG_GAIN_RANGE) + .c_str() + << ": " << sl::toString(err).c_str()); + } + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " + << sl::toString( + sl::VIDEO_SETTINGS::AUTO_ANALOG_GAIN_RANGE) + .c_str() + << ": " << sl::toString(err).c_str()); + } +} + +void ZedCamera::applyZEDXAutoDigitalGainRange() +{ + // ----> TODO(Walter) Remove this check when fixed in ZED SDK + if (mCamRealModel == sl::MODEL::VIRTUAL_ZED_X) { + DEBUG_VD( + "Auto Digital Gain Range not supported for VIRTUAL_ZED_X model. " + "Skipping setting."); + return; + } + // <---- TODO(Walter) Remove this check when fixed in ZED SDK + + sl::ERROR_CODE err; + int value_min, value_max; + err = mZed->getCameraSettings( + sl::VIDEO_SETTINGS::AUTO_DIGITAL_GAIN_RANGE, + value_min, value_max); + if (err == sl::ERROR_CODE::SUCCESS && + (value_min != mGmslAutoDigitalGainRangeMin || + value_max != mGmslAutoDigitalGainRangeMax)) + { + err = mZed->setCameraSettings( + sl::VIDEO_SETTINGS::AUTO_DIGITAL_GAIN_RANGE, + mGmslAutoDigitalGainRangeMin, + mGmslAutoDigitalGainRangeMax); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Error setting " + << sl::toString( + sl::VIDEO_SETTINGS::AUTO_DIGITAL_GAIN_RANGE) + .c_str() + << ": " << sl::toString(err).c_str()); + } +} + +void ZedCamera::applyZEDXDenoising() +{ + if (!mStreamMode) { + sl::ERROR_CODE err; + sl::VIDEO_SETTINGS setting = sl::VIDEO_SETTINGS::DENOISING; + int value; + err = mZed->getCameraSettings(setting, value); + if (err == sl::ERROR_CODE::SUCCESS && value != mGmslDenoising) { + err = mZed->setCameraSettings(setting, mGmslDenoising); + DEBUG_STREAM_CTRL( + "New setting for " << sl::toString(setting).c_str() + << ": " << mGmslDenoising + << " [Old " << value << "]"); + } + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << sl::toString(setting).c_str() + << ": " + << sl::toString(err).c_str()); + } + } +} + +void ZedCamera::processVideoDepth() +{ + DEBUG_VD("=== Process Video/Depth ==="); + + // If no subscribers, do not retrieve data + if (areVideoDepthSubscribed()) { + DEBUG_VD(" * [processVideoDepth] vd_lock -> defer"); + std::unique_lock vd_lock(mVdMutex, std::defer_lock); + + DEBUG_VD(" * [processVideoDepth] vd_lock -> try_lock"); + if (vd_lock.try_lock()) { + bool gpu = false; +#ifdef FOUND_ISAAC_ROS_NITROS + if (!_nitrosDisabled) { + gpu = true; + } +#endif + retrieveVideoDepth(gpu); + + // Signal Video/Depth thread that a new pointcloud is ready + mVdDataReadyCondVar.notify_one(); + mVdDataReady = true; + mVdPublishing = true; + } else { + DEBUG_VD(" * [processVideoDepth] vd_lock not locked"); + } + } else { + mVdPublishing = false; + DEBUG_VD(" * [processVideoDepth] No video/depth subscribers"); + + // Publish camera infos even if no video/depth subscribers are present + publishCameraInfos(); + } + DEBUG_VD("=== Process Video/Depth done ==="); +} + +void ZedCamera::retrieveVideoDepth(bool gpu) +{ + DEBUG_VD(" *** Retrieving Video/Depth Data ***"); + mRgbSubscribed = false; + bool retrieved_video = false; + bool retrieved_depth = false; + + DEBUG_STREAM_VD(" *** Retrieving Video Data ***"); + retrieved_video |= retrieveLeftImage(gpu); + retrieved_video |= retrieveLeftRawImage(gpu); + retrieved_video |= retrieveRightImage(gpu); + retrieved_video |= retrieveRightRawImage(gpu); + retrieved_video |= retrieveLeftGrayImage(gpu); + retrieved_video |= retrieveLeftRawGrayImage(gpu); + retrieved_video |= retrieveRightGrayImage(gpu); + retrieved_video |= retrieveRightRawGrayImage(gpu); + + if (retrieved_video) { + DEBUG_STREAM_VD(" *** Video Data retrieved ***"); + } + + DEBUG_STREAM_VD(" *** Retrieving Depth Data ***"); + retrieved_depth |= retrieveDepthMap(gpu); + retrieved_depth |= retrieveConfidence(gpu); + retrieved_depth |= retrieveDisparity(); + retrieved_depth |= retrieveDepthInfo(); + + if (retrieved_depth) { + DEBUG_STREAM_VD(" *** Depth Data retrieved ***"); + } + + if (retrieved_video || retrieved_depth) { + mSdkGrabTS = mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE); + auto now = mZed->getTimestamp(sl::TIME_REFERENCE::CURRENT); + DEBUG_STREAM_VD( + " * Video/Depth Latency: " << static_cast(now - mSdkGrabTS) * 1e-9 << " sec"); + } + + DEBUG_VD(" *** Retrieving Video/Depth Data DONE ***"); +} + +// Helper functions for retrieveVideoDepth() + +bool ZedCamera::retrieveLeftImage(bool gpu) +{ + if (mRgbSubCount + mLeftSubCount + mStereoSubCount > 0) { + DEBUG_VD(" * Retrieving Left image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatLeft, +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + m24bitMode ? sl::VIEW::LEFT_BGR : sl::VIEW::LEFT_BGRA, +#else + sl::VIEW::LEFT, +#endif + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + mRgbSubscribed = true; + DEBUG_STREAM_VD(" * Left image retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveLeftRawImage(bool gpu) +{ + if (mRgbRawSubCount + mLeftRawSubCount + mStereoRawSubCount > 0) { + DEBUG_VD(" * Retrieving Left raw image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatLeftRaw, +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + m24bitMode ? sl::VIEW::LEFT_UNRECTIFIED_BGR : sl::VIEW::LEFT_UNRECTIFIED_BGRA, +#else + sl::VIEW::LEFT_UNRECTIFIED, +#endif + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD(" * Left raw image retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveRightImage(bool gpu) +{ + if (mRightSubCount + mStereoSubCount > 0) { + DEBUG_VD(" * Retrieving Right image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatRight, +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + m24bitMode ? sl::VIEW::RIGHT_BGR : sl::VIEW::RIGHT_BGRA, +#else + sl::VIEW::RIGHT, +#endif + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD(" * Right image retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveRightRawImage(bool gpu) +{ + if (mRightRawSubCount + mStereoRawSubCount > 0) { + DEBUG_VD(" * Retrieving Right raw image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatRightRaw, +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + m24bitMode ? sl::VIEW::RIGHT_UNRECTIFIED_BGR : sl::VIEW::RIGHT_UNRECTIFIED_BGRA, +#else + sl::VIEW::RIGHT_UNRECTIFIED, +#endif + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD(" * Right raw image retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveLeftGrayImage(bool gpu) +{ + if (mRgbGraySubCount + mLeftGraySubCount > 0) { + DEBUG_VD(" * Retrieving Left gray image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatLeftGray, sl::VIEW::LEFT_GRAY, + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD(" * Left gray image retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveLeftRawGrayImage(bool gpu) +{ + if (mRgbGrayRawSubCount + mLeftGrayRawSubCount > 0) { + DEBUG_VD(" * Retrieving Left gray raw image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatLeftRawGray, sl::VIEW::LEFT_UNRECTIFIED_GRAY, + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD( + " * Left gray raw image retrieved into " << (gpu ? "GPU" : "CPU") << + " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveRightGrayImage(bool gpu) +{ + if (mRightGraySubCount > 0) { + DEBUG_VD(" * Retrieving Right gray image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatRightGray, sl::VIEW::RIGHT_GRAY, + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD(" * Right gray image retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveRightRawGrayImage(bool gpu) +{ + if (mRightGrayRawSubCount > 0) { + DEBUG_VD(" * Retrieving Right gray raw image"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveImage( + mMatRightRawGray, sl::VIEW::RIGHT_UNRECTIFIED_GRAY, + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD( + " * Right gray raw image retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveDepthMap(bool gpu) +{ + if (mDepthSubCount > 0 || mDepthInfoSubCount > 0) { + DEBUG_STREAM_VD(" * Retrieving Depth Map"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveMeasure( + mMatDepth, sl::MEASURE::DEPTH, + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD(" * Depth map retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveDisparity() +{ + if (mDisparitySubCount > 0) { + DEBUG_STREAM_VD(" * Retrieving Disparity"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveMeasure( + mMatDisp, sl::MEASURE::DISPARITY, + sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_VD(" * Disparity map retrieved"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveConfidence(bool gpu) +{ + if (mConfMapSubCount > 0) { + DEBUG_STREAM_VD(" * Retrieving Confidence"); + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->retrieveMeasure( + mMatConf, sl::MEASURE::CONFIDENCE, + gpu ? sl::MEM::GPU : sl::MEM::CPU, mMatResol); + if (ok) { + DEBUG_STREAM_VD(" * Confidence map retrieved into " << (gpu ? "GPU" : "CPU") << " memory"); + } + return ok; + } + return false; +} + +bool ZedCamera::retrieveDepthInfo() +{ + if (mDepthInfoSubCount > 0) { + bool ok = sl::ERROR_CODE::SUCCESS == + mZed->getCurrentMinMaxDepth(mMinDepth, mMaxDepth); + if (ok) { + DEBUG_VD(" * Depth info retrieved"); + } + return ok; + } + return false; +} + +void ZedCamera::publishVideoDepth(rclcpp::Time & out_pub_ts) +{ + DEBUG_VD("=== Publish Video and Depth topics === "); + sl_tools::StopWatch vdElabTimer(get_clock()); + + checkRgbDepthSync(); + + vdElabTimer.tic(); + rclcpp::Time timeStamp; + + if (!checkGrabAndUpdateTimestamp(timeStamp)) { + return; + } + + publishLeftAndRgbImages(timeStamp); + publishLeftRawAndRgbRawImages(timeStamp); + publishLeftGrayAndRgbGrayImages(timeStamp); + publishLeftRawGrayAndRgbRawGrayImages(timeStamp); + publishRightImages(timeStamp); + publishRightRawImages(timeStamp); + publishRightGrayImages(timeStamp); + publishRightRawGrayImages(timeStamp); + publishStereoImages(timeStamp); + publishStereoRawImages(timeStamp); + publishDepthImage(timeStamp); + publishConfidenceMap(timeStamp); + publishDisparityImage(timeStamp); + publishDepthInfo(timeStamp); + + + mVideoDepthElabMean_sec->addValue(vdElabTimer.toc()); + + out_pub_ts = timeStamp; + + DEBUG_VD("=== Video and Depth topics published === "); +} + +// Helper functions for publishVideoDepth + +void ZedCamera::checkRgbDepthSync() +{ + sl::Timestamp ts_rgb = 0; + sl::Timestamp ts_depth = 0; + + if (mRgbSubscribed && (mDepthSubCount > 0 || mDepthInfoSubCount > 0)) { + ts_rgb = mMatLeft.timestamp; + ts_depth = mMatDepth.timestamp; + + if (mRgbSubscribed && + (ts_rgb.data_ns != 0 && (ts_depth.data_ns != ts_rgb.data_ns))) + { + RCLCPP_WARN_STREAM( + get_logger(), + " !!!!! DEPTH/RGB ASYNC !!!!! - Delta: " + << 1e-9 * static_cast(ts_depth - ts_rgb) + << " sec"); + RCLCPP_WARN( + get_logger(), + " NOTE: this should never happen, please contact the node " + "maintainer in case you get this warning."); + } + } +} + +bool ZedCamera::checkGrabAndUpdateTimestamp(rclcpp::Time & out_pub_ts) +{ + if (mSdkGrabTS.getNanoseconds() == mLastTs_grab.getNanoseconds()) { + out_pub_ts = TIMEZERO_ROS; + DEBUG_VD(" * publishVideoDepth: ignoring not update data"); + DEBUG_STREAM_VD( + " * Latest Ts: " << mLastTs_grab.getNanoseconds() << " - New Ts: " << + mSdkGrabTS.getNanoseconds()); + return false; + } + + if (mSdkGrabTS.data_ns != 0) { + if (!mSvoMode) { + double period_sec = + static_cast(mSdkGrabTS.data_ns - mLastTs_grab.data_ns) / 1e9; + DEBUG_STREAM_VD( + " * VIDEO/DEPTH PUB LAST PERIOD: " + << period_sec << " sec @" << 1. / period_sec << " Hz / Expected: " << 1. / mVdPubRate << " sec @" << mVdPubRate << + " Hz"); + + mVideoDepthPeriodMean_sec->addValue(period_sec); + DEBUG_STREAM_VD( + " * VIDEO/DEPTH PUB MEAN PERIOD: " + << mVideoDepthPeriodMean_sec->getAvg() << " sec @" + << 1. / mVideoDepthPeriodMean_sec->getAvg() << " Hz / Expected: " << 1. / mVdPubRate << " sec @" << mVdPubRate << + " Hz"); + mLastTs_grab = mSdkGrabTS; + } + } + + if (mSvoMode) { + out_pub_ts = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + } else if (mSimMode) { + if (mUseSimTime) { + out_pub_ts = get_clock()->now(); + } else { + out_pub_ts = mUsePubTimestamps ? get_clock()->now() : + sl_tools::slTime2Ros(mZed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } + } else { + out_pub_ts = mUsePubTimestamps ? get_clock()->now() : sl_tools::slTime2Ros( + mSdkGrabTS, + get_clock()->get_clock_type()); + } + return true; +} + +void ZedCamera::publishLeftAndRgbImages(const rclcpp::Time & t) +{ + if (mLeftSubCount > 0) { + DEBUG_STREAM_VD(" * mLeftSubCount: " << mLeftSubCount); + + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeft, mPubLeft, mPubLeftCamInfo, mPubLeftCamInfoTrans, + mLeftCamInfoMsg, mLeftCamOptFrameId, t); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeft, mNitrosPubLeft, mPubLeftCamInfo, mPubLeftCamInfoTrans, mLeftCamInfoMsg, + mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubLeftCamInfo, mLeftCamInfoMsg, t); + publishCameraInfo(mPubLeftCamInfoTrans, mLeftCamInfoMsg, t); + } + + if (mRgbSubCount > 0) { + DEBUG_STREAM_VD(" * mRgbSubCount: " << mRgbSubCount); + + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeft, mPubRgb, mPubRgbCamInfo, mPubRgbCamInfoTrans, mLeftCamInfoMsg, + mLeftCamOptFrameId, t); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeft, mNitrosPubRgb, mPubRgbCamInfo, mPubRgbCamInfoTrans, mLeftCamInfoMsg, + mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRgbCamInfo, mLeftCamInfoMsg, t); + publishCameraInfo(mPubRgbCamInfoTrans, mLeftCamInfoMsg, t); + } +} + +void ZedCamera::publishLeftRawAndRgbRawImages(const rclcpp::Time & t) +{ + if (mLeftRawSubCount > 0) { + DEBUG_STREAM_VD(" * mLeftRawSubCount: " << mLeftRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeftRaw, + mPubRawLeft, + mPubRawLeftCamInfo, + mPubRawLeftCamInfoTrans, + mLeftCamInfoRawMsg, + mLeftCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeftRaw, mNitrosPubRawLeft, mPubRawLeftCamInfo, mPubRawLeftCamInfoTrans, + mLeftCamInfoRawMsg, mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRawLeftCamInfo, mLeftCamInfoRawMsg, t); + publishCameraInfo(mPubRawLeftCamInfoTrans, mLeftCamInfoRawMsg, t); + } + + if (mRgbRawSubCount > 0) { + DEBUG_STREAM_VD(" * mRgbRawSubCount: " << mRgbRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeftRaw, mPubRawRgb, mPubRawRgbCamInfo, mPubRawRgbCamInfoTrans, + mLeftCamInfoRawMsg, mLeftCamOptFrameId, t); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeftRaw, mNitrosPubRawRgb, mPubRawRgbCamInfo, mPubRawRgbCamInfoTrans, + mLeftCamInfoRawMsg, mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRawRgbCamInfo, mLeftCamInfoRawMsg, t); + publishCameraInfo(mPubRawRgbCamInfoTrans, mLeftCamInfoRawMsg, t); + } +} + +void ZedCamera::publishLeftGrayAndRgbGrayImages(const rclcpp::Time & t) +{ + if (mLeftGraySubCount > 0) { + DEBUG_STREAM_VD(" * mLeftGraySubCount: " << mLeftGraySubCount); + + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeftGray, + mPubLeftGray, + mPubLeftGrayCamInfo, + mPubLeftGrayCamInfoTrans, + mLeftCamInfoMsg, + mLeftCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeftGray, mNitrosPubLeftGray, mPubLeftGrayCamInfo, mPubLeftGrayCamInfoTrans, + mLeftCamInfoMsg, mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubLeftGrayCamInfo, mLeftCamInfoMsg, t); + publishCameraInfo(mPubLeftGrayCamInfoTrans, mLeftCamInfoMsg, t); + } + + if (mRgbGraySubCount > 0) { + DEBUG_STREAM_VD(" * mRgbGraySubCount: " << mRgbGraySubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeftGray, + mPubRgbGray, + mPubRgbGrayCamInfo, + mPubRgbGrayCamInfoTrans, + mLeftCamInfoMsg, + mLeftCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeftGray, mNitrosPubRgbGray, mPubRgbGrayCamInfo, mPubRgbGrayCamInfoTrans, + mLeftCamInfoMsg, mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRgbGrayCamInfo, mLeftCamInfoMsg, t); + publishCameraInfo(mPubRgbGrayCamInfoTrans, mLeftCamInfoMsg, t); + } +} + +void ZedCamera::publishLeftRawGrayAndRgbRawGrayImages(const rclcpp::Time & t) +{ + if (mLeftGrayRawSubCount > 0) { + DEBUG_STREAM_VD(" * mLeftGrayRawSubCount: " << mLeftGrayRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeftRawGray, + mPubRawLeftGray, + mPubRawLeftGrayCamInfo, + mPubRawLeftGrayCamInfoTrans, + mLeftCamInfoRawMsg, + mLeftCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeftRawGray, mNitrosPubRawLeftGray, mPubRawLeftGrayCamInfo, mPubRawLeftGrayCamInfoTrans, + mLeftCamInfoRawMsg, mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRawLeftGrayCamInfo, mLeftCamInfoRawMsg, t); + publishCameraInfo(mPubRawLeftGrayCamInfoTrans, mLeftCamInfoRawMsg, t); + } + + if (mRgbGrayRawSubCount > 0) { + DEBUG_STREAM_VD(" * mRgbGrayRawSubCount: " << mRgbGrayRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatLeftRawGray, + mPubRawRgbGray, + mPubRawRgbGrayCamInfo, + mPubRawRgbGrayCamInfoTrans, + mLeftCamInfoRawMsg, + mLeftCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatLeftRawGray, mNitrosPubRawRgbGray, mPubRawRgbGrayCamInfo, mPubRawRgbGrayCamInfoTrans, + mLeftCamInfoRawMsg, mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRawRgbGrayCamInfo, mLeftCamInfoRawMsg, t); + publishCameraInfo(mPubRawRgbGrayCamInfoTrans, mLeftCamInfoRawMsg, t); + } +} + +void ZedCamera::publishRightImages(const rclcpp::Time & t) +{ + if (mRightSubCount > 0) { + DEBUG_STREAM_VD(" * mRightSubCount: " << mRightSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatRight, mPubRight, mPubRightCamInfo, mPubRightCamInfoTrans, + mRightCamInfoMsg, mRightCamOptFrameId, t); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatRight, mNitrosPubRight, mPubRightCamInfo, mPubRightCamInfoTrans, + mRightCamInfoMsg, mRightCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRightCamInfo, mRightCamInfoMsg, t); + publishCameraInfo(mPubRightCamInfoTrans, mRightCamInfoMsg, t); + } +} + +void ZedCamera::publishRightRawImages(const rclcpp::Time & t) +{ + if (mRightRawSubCount > 0) { + DEBUG_STREAM_VD(" * mRightRawSubCount: " << mRightRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatRightRaw, + mPubRawRight, + mPubRawRightCamInfo, + mPubRawRightCamInfoTrans, + mRightCamInfoRawMsg, + mRightCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatRightRaw, mNitrosPubRawRight, mPubRawRightCamInfo, mPubRawRightCamInfoTrans, + mRightCamInfoRawMsg, mRightCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRawRightCamInfo, mRightCamInfoRawMsg, t); + publishCameraInfo(mPubRawRightCamInfoTrans, mRightCamInfoRawMsg, t); + } +} + +void ZedCamera::publishRightGrayImages(const rclcpp::Time & t) +{ + if (mRightGraySubCount > 0) { + DEBUG_STREAM_VD(" * mRightGraySubCount: " << mRightGraySubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatRightGray, + mPubRightGray, + mPubRightGrayCamInfo, + mPubRightGrayCamInfoTrans, + mRightCamInfoMsg, + mRightCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatRightGray, mNitrosPubRightGray, mPubRightGrayCamInfo, mPubRightGrayCamInfoTrans, + mRightCamInfoMsg, mRightCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRightGrayCamInfo, mRightCamInfoMsg, t); + publishCameraInfo(mPubRightGrayCamInfoTrans, mRightCamInfoMsg, t); + } +} + +void ZedCamera::publishRightRawGrayImages(const rclcpp::Time & t) +{ + if (mRightGrayRawSubCount > 0) { + DEBUG_STREAM_VD(" * mRightGrayRawSubCount: " << mRightGrayRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatRightRawGray, + mPubRawRightGray, + mPubRawRightGrayCamInfo, + mPubRawRightGrayCamInfoTrans, + mRightCamInfoRawMsg, + mRightCamOptFrameId, + t + ); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatRightRawGray, mNitrosPubRawRightGray, mPubRawRightGrayCamInfo, + mPubRawRightGrayCamInfoTrans, + mRightCamInfoRawMsg, mRightCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubRawRightGrayCamInfo, mRightCamInfoRawMsg, t); + publishCameraInfo(mPubRawRightGrayCamInfoTrans, mRightCamInfoRawMsg, t); + } +} + +void ZedCamera::publishStereoImages(const rclcpp::Time & t) +{ + if (mStereoSubCount > 0) { + DEBUG_STREAM_VD(" * mStereoSubCount: " << mStereoSubCount); + auto combined = sl_tools::imagesToROSmsg( + mMatLeft, mMatRight, mCenterFrameId, t, mUsePubTimestamps); + DEBUG_STREAM_VD(" * Publishing SIDE-BY-SIDE message"); + try { + mPubStereo.publish(std::move(combined)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } + } +} + +void ZedCamera::publishStereoRawImages(const rclcpp::Time & t) +{ + if (mStereoRawSubCount > 0) { + DEBUG_STREAM_VD(" * mStereoRawSubCount: " << mStereoRawSubCount); + auto combined = sl_tools::imagesToROSmsg( + mMatLeftRaw, mMatRightRaw, mCenterFrameId, t, mUsePubTimestamps); + DEBUG_STREAM_VD(" * Publishing SIDE-BY-SIDE RAW message"); + try { + mPubRawStereo.publish(std::move(combined)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } + } +} + +void ZedCamera::publishDepthImage(const rclcpp::Time & t) +{ + if (mDepthSubCount > 0) { + publishDepthMapWithInfo(mMatDepth, t); + } else { + publishCameraInfo(mPubDepthCamInfo, mLeftCamInfoMsg, t); + publishCameraInfo(mPubDepthCamInfoTrans, mLeftCamInfoMsg, t); + } +} + +void ZedCamera::publishConfidenceMap(const rclcpp::Time & t) +{ + if (mConfMapSubCount > 0) { + DEBUG_STREAM_VD(" * mConfMapSubCount: " << mConfMapSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + mMatConf, mPubConfMap, mPubConfMapCamInfo, mPubConfMapCamInfoTrans, + mLeftCamInfoMsg, mLeftCamOptFrameId, t); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + mMatConf, mNitrosPubConfMap, mPubConfMapCamInfo, mPubConfMapCamInfoTrans, + mLeftCamInfoMsg, mLeftCamOptFrameId, t); +#endif + } + } else { + publishCameraInfo(mPubConfMapCamInfo, mLeftCamInfoMsg, t); + publishCameraInfo(mPubConfMapCamInfoTrans, mLeftCamInfoMsg, t); + } +} + +void ZedCamera::publishDisparityImage(const rclcpp::Time & t) +{ + if (mDisparitySubCount > 0) { + publishDisparity(mMatDisp, t); + } +} + +void ZedCamera::publishDepthInfo(const rclcpp::Time & t) +{ + if (mDepthInfoSubCount > 0) { + auto depthInfoMsg = std::make_unique(); + depthInfoMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + depthInfoMsg->header.frame_id = mDepthOptFrameId; + depthInfoMsg->min_depth = mMinDepth; + depthInfoMsg->max_depth = mMaxDepth; + + DEBUG_STREAM_VD(" * Publishing DEPTH INFO message"); + try { + if (mPubDepthInfo) { + mPubDepthInfo->publish(std::move(depthInfoMsg)); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } + } +} + +void ZedCamera::publishCameraInfo( + const camInfoPub & infoPub, + camInfoMsgPtr & camInfoMsg, + const rclcpp::Time & t) +{ + auto ts = mUsePubTimestamps ? get_clock()->now() : t; + camInfoMsg->header.stamp = ts; + + if (infoPub) { + if (count_subscribers(infoPub->get_topic_name()) > 0) { + infoPub->publish(*camInfoMsg); + DEBUG_STREAM_VD(" * Camera Info message published: " << infoPub->get_topic_name()); + DEBUG_STREAM_VD(" * Timestamp: " << ts.nanoseconds() << " nsec"); + } + } +} + +void ZedCamera::publishImageWithInfo( + const sl::Mat & img, + const image_transport::Publisher & pubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t) +{ + auto image = sl_tools::imageToROSmsg(img, imgFrameId, t, mUsePubTimestamps); + DEBUG_STREAM_VD( + " * Publishing IMAGE message: " << (mUsePubTimestamps ? get_clock()->now() : t).nanoseconds() << + " nsec"); + try { + publishCameraInfo(infoPub, camInfoMsg, image->header.stamp); + publishCameraInfo(infoPubTrans, camInfoMsg, image->header.stamp); + pubImg.publish(std::move(image)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } +} + +#ifdef FOUND_ISAAC_ROS_NITROS +void ZedCamera::publishImageWithInfo( + const sl::Mat & img, + const nitrosImgPub & nitrosPubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t) +{ + DEBUG_STREAM_VD(" * Publishing NITROS IMAGE message: " << t.nanoseconds() << " nsec"); + try { + size_t dpitch = img.getWidthBytes(); + size_t spitch = img.getStepBytes(sl::MEM::GPU); // SL Mat can be padded + + DEBUG_NITROS( + " * Nitros Image publish - Width: %zu Height: %zu PixelBytes: %zu " + "Spitch: %zu Dpitch: %zu", + img.getWidth(), img.getHeight(), img.getPixelBytes(), spitch, dpitch); + + size_t dbuffer_size{spitch * img.getHeight()}; + void * dbuffer; + CUDA_CHECK(cudaMalloc(&dbuffer, dbuffer_size)); + + DEBUG_NITROS("Sent CUDA Image buffer with memory at: %p", dbuffer); + + // Copy data bytes to CUDA buffer + CUDA_CHECK( + cudaMemcpy2D( + dbuffer, + dpitch, + img.getPtr(sl::MEM::GPU), + spitch, + img.getWidth() * img.getPixelBytes(), img.getHeight(), + cudaMemcpyDeviceToDevice)); + + // Adding header data + std_msgs::msg::Header header; + header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + header.frame_id = imgFrameId; + + auto encoding = img_encodings::BGRA8; // Default encoding + if (img.getDataType() == sl::MAT_TYPE::U8_C1) { + encoding = img_encodings::MONO8; // Mono image + } else if (img.getDataType() == sl::MAT_TYPE::U8_C3) { + encoding = img_encodings::BGR8; // BGR image + } else if (img.getDataType() == sl::MAT_TYPE::F32_C1) { + encoding = img_encodings::TYPE_32FC1; // Float image + } + + // Create NitrosImage wrapping CUDA buffer + nvidia::isaac_ros::nitros::NitrosImage nitros_image = + nvidia::isaac_ros::nitros::NitrosImageBuilder() + .WithHeader(header) + .WithEncoding(encoding) + .WithDimensions(img.getHeight(), img.getWidth()) + .WithGpuData(dbuffer) + //.WithGpuData(img.getPtr(sl::MEM::GPU)) // TODO: Enable direct GPU memory sharing when supported by Isaac ROS. + .Build(); + + if (nitrosPubImg) { + nitrosPubImg->publish(nitros_image); + } + publishCameraInfo(infoPub, camInfoMsg, header.stamp); + publishCameraInfo(infoPubTrans, camInfoMsg, header.stamp); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } +} +#endif + +void ZedCamera::publishDepthMapWithInfo( + const sl::Mat & depth, + const rclcpp::Time & t) +{ + mLeftCamInfoMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + + if (_nitrosDisabled) { + if (!mOpenniDepthMode) { + auto depth_img = sl_tools::imageToROSmsg(depth, mDepthOptFrameId, t, mUsePubTimestamps); + DEBUG_STREAM_VD( + " * Publishing DEPTH message: " << t.nanoseconds() + << " nsec"); + try { + mPubDepth.publish(std::move(depth_img)); + publishCameraInfo(mPubDepthCamInfo, mLeftCamInfoMsg, t); + publishCameraInfo(mPubDepthCamInfoTrans, mLeftCamInfoMsg, t); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } + return; + } + + // OPENNI CONVERSION (meter -> millimeters - float32 -> uint16) + auto openniDepthMsg = std::make_unique(); + + openniDepthMsg->header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + openniDepthMsg->header.frame_id = mDepthOptFrameId; + openniDepthMsg->height = depth.getHeight(); + openniDepthMsg->width = depth.getWidth(); + + int num = 1; // for endianness detection + openniDepthMsg->is_bigendian = !(*reinterpret_cast(&num) == 1); + + openniDepthMsg->step = openniDepthMsg->width * sizeof(uint16_t); + openniDepthMsg->encoding = sensor_msgs::image_encodings::MONO16; + + size_t size = openniDepthMsg->step * openniDepthMsg->height; + openniDepthMsg->data.resize(size); + + uint16_t * data = reinterpret_cast(&openniDepthMsg->data[0]); + + int dataSize = openniDepthMsg->width * openniDepthMsg->height; + sl::float1 * depthDataPtr = depth.getPtr(); + + for (int i = 0; i < dataSize; i++) { + *(data++) = static_cast( + std::round(*(depthDataPtr++) * 1000)); // in mm, rounded + } + + DEBUG_STREAM_VD(" * Publishing OPENNI DEPTH message"); + try { + mPubDepth.publish(std::move(openniDepthMsg)); + publishCameraInfo(mPubDepthCamInfo, mLeftCamInfoMsg, t); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + DEBUG_STREAM_VD(" * Publishing NITROS DEPTH IMAGE message: " << t.nanoseconds() << " nsec"); + try { + size_t dpitch = depth.getWidthBytes(); + size_t spitch = depth.getStepBytes(sl::MEM::GPU); // SL Mat can be padded + + size_t dbuffer_size{dpitch * depth.getHeight()}; + void * dbuffer; + CUDA_CHECK(cudaMalloc(&dbuffer, dbuffer_size)); + + DEBUG_NITROS("Sent Depth CUDA buffer with memory at: %p", dbuffer); + + // Copy data bytes to CUDA buffer + CUDA_CHECK( + cudaMemcpy2D( + dbuffer, + dpitch, + depth.getPtr(sl::MEM::GPU), + spitch, + depth.getWidth() * depth.getPixelBytes(), depth.getHeight(), + cudaMemcpyDeviceToDevice)); + + // Adding header data + std_msgs::msg::Header header; + header.stamp = mUsePubTimestamps ? get_clock()->now() : t; + header.frame_id = mDepthOptFrameId; + + // Create NitrosImage wrapping CUDA buffer + nvidia::isaac_ros::nitros::NitrosImage nitros_image = + nvidia::isaac_ros::nitros::NitrosImageBuilder() + .WithHeader(header) + .WithEncoding(img_encodings::TYPE_32FC1) + .WithDimensions(depth.getHeight(), depth.getWidth()) + .WithGpuData(dbuffer) + //.WithGpuData(depth.getPtr(sl::MEM::GPU)) // TODO: Enable direct GPU memory sharing when supported by Isaac ROS. + .Build(); + + if (mNitrosPubDepth) { + mNitrosPubDepth->publish(nitros_image); + } + publishCameraInfo(mPubDepthCamInfo, mLeftCamInfoMsg, t); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } +#endif + } +} + +void ZedCamera::publishDisparity( + const sl::Mat & disparity, + const rclcpp::Time & t) +{ + sl::CameraInformation zedParam = mZed->getCameraInformation(mMatResol); + + std::unique_ptr disparity_image = + sl_tools::imageToROSmsg(disparity, mDepthOptFrameId, t, mUsePubTimestamps); + + auto disparityMsg = std::make_unique(); + disparityMsg->image = *disparity_image.get(); + disparityMsg->header = disparityMsg->image.header; + disparityMsg->f = + zedParam.camera_configuration.calibration_parameters.left_cam.fx; + disparityMsg->t = zedParam.camera_configuration.calibration_parameters + .getCameraBaseline(); + disparityMsg->min_disparity = + disparityMsg->f * disparityMsg->t / + mZed->getInitParameters().depth_maximum_distance; + disparityMsg->max_disparity = + disparityMsg->f * disparityMsg->t / + mZed->getInitParameters().depth_minimum_distance; + + DEBUG_STREAM_VD(" * Publishing DISPARITY message"); + try { + if (mPubDisparity) { + mPubDisparity->publish(std::move(disparityMsg)); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } +} + +void ZedCamera::processPointCloud() +{ + DEBUG_PC("=== Process Point Cloud ==="); + + if (isPointCloudSubscribed()) { + // Run the point cloud conversion asynchronously to avoid slowing down + // all the program + // Retrieve raw pointCloud data if latest Pointcloud is ready + DEBUG_PC(" * [processPointCloud] pc_lock -> defer"); + std::unique_lock pc_lock(mPcMutex, std::defer_lock); + + DEBUG_PC(" * [processPointCloud] pc_lock -> try_lock"); + if (pc_lock.try_lock()) { + DEBUG_STREAM_PC( + " * [processPointCloud] Retrieving point cloud size: " << mPcResol.width << "x" << + mPcResol.height); + auto pc_err = mZed->retrieveMeasure( + mMatCloud, sl::MEASURE::XYZBGRA, sl::MEM::CPU, + mPcResol); + if (pc_err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), + "Point cloud retrieve error: " << sl::toString(pc_err)); + return; + } + DEBUG_STREAM_PC( + " * [processPointCloud] Retrieved point cloud size: " << mMatCloud.getWidth() << "x" << + mMatCloud.getHeight()); + + // Signal Pointcloud thread that a new pointcloud is ready + mPcDataReadyCondVar.notify_one(); + mPcDataReady = true; + mPcPublishing = true; + + DEBUG_STREAM_PC( + " * [processPointCloud] Extracted point cloud: " << mMatCloud.getInfos().c_str() ); + } else { + DEBUG_PC(" * [processPointCloud] pc_lock not locked"); + } + } else { + mPcPublishing = false; + DEBUG_PC(" * [processPointCloud] No point cloud subscribers"); + } + + DEBUG_PC("=== Process Point Cloud done ==="); +} + +bool ZedCamera::isPointCloudSubscribed() +{ + size_t cloudSubCount = 0; + try { +#ifdef FOUND_POINT_CLOUD_TRANSPORT + cloudSubCount = mPubCloud.getNumSubscribers(); +#else + if (mPubCloud) { + cloudSubCount = count_subscribers(mPubCloud->get_topic_name()); + } +#endif + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_PC( + " * [isPointCloudSubscribed] Exception while counting point cloud " + "subscribers"); + return false; + } + + return cloudSubCount > 0; +} + +void ZedCamera::publishPointCloud() +{ + sl_tools::StopWatch pcElabTimer(get_clock()); + + int width = mPcResol.width; + int height = mPcResol.height; + + int ptsCount = width * height; + + rclcpp::Time stamp; + if (mSvoMode) { + stamp = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + } else if (mSimMode) { + if (mUseSimTime) { + stamp = mUsePubTimestamps ? get_clock()->now() : mFrameTimestamp; + } else { + stamp = mUsePubTimestamps ? get_clock()->now() : sl_tools::slTime2Ros( + mMatCloud.timestamp); + } + } else { + stamp = mUsePubTimestamps ? get_clock()->now() : sl_tools::slTime2Ros( + mMatCloud.timestamp); + } + + // ---> Check that timestamp is not the same of the latest + // published pointcloud. Avoid publishing the same old data. + if (mLastTs_pc == stamp) { + DEBUG_STREAM_PC(" * [publishPointCloud] ignoring not update data"); + return; + } + mLastTs_pc = stamp; + // <--- Check timestamp + + // Resize the reusable message buffer only when resolution changes + if (static_cast(mPcMsg.width) != width || + static_cast(mPcMsg.height) != height) + { + mPcMsg.header.frame_id = mPointCloudFrameId; + + int val = 1; + mPcMsg.is_bigendian = !(*reinterpret_cast(&val) == 1); + mPcMsg.is_dense = false; + + mPcMsg.width = width; + mPcMsg.height = height; + + sensor_msgs::PointCloud2Modifier modifier(mPcMsg); + modifier.setPointCloud2Fields( + 4, "x", 1, sensor_msgs::msg::PointField::FLOAT32, "y", 1, + sensor_msgs::msg::PointField::FLOAT32, "z", 1, + sensor_msgs::msg::PointField::FLOAT32, "rgb", 1, + sensor_msgs::msg::PointField::FLOAT32); + } + + mPcMsg.header.stamp = stamp; + + sl::Vector4 * cpu_cloud = mMatCloud.getPtr(); + + // Data copy into reused buffer + float * ptCloudPtr = reinterpret_cast(&mPcMsg.data[0]); + memcpy( + ptCloudPtr, reinterpret_cast(cpu_cloud), + ptsCount * 4 * sizeof(float)); + + // Pointcloud publishing + DEBUG_PC(" * [publishPointCloud] Publishing POINT CLOUD message"); +#ifdef FOUND_POINT_CLOUD_TRANSPORT + try { + mPubCloud.publish(mPcMsg); + } catch (std::system_error & e) { + DEBUG_STREAM_PC(" * [publishPointCloud] Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_PC(" * [publishPointCloud] Message publishing generic exception"); + } +#else + try { + if (mPubCloud) { + mPubCloud->publish(mPcMsg); + } + } catch (std::system_error & e) { + DEBUG_STREAM_PC(" * [publishPointCloud] Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_PC(" * [publishPointCloud] Message publishing generic exception"); + } +#endif + + // Publish freq calculation + double mean = mPcPeriodMean_sec->addValue(mPcFreqTimer.toc()); + mPcFreqTimer.tic(); + + // Point cloud elaboration time + mPcProcMean_sec->addValue(pcElabTimer.toc()); + DEBUG_STREAM_PC(" * [publishPointCloud] Point cloud freq: " << 1. / mean); +} + +void ZedCamera::threadFunc_videoDepthElab() +{ + DEBUG_STREAM_VD("Video Depth thread started"); + + // Set the name of the videoDepthElab thread for easier identification in + // system monitors + pthread_setname_np(pthread_self(), (get_name() + std::string("_videoDepthElab")).c_str()); + + setupVideoDepthThread(); + + mVdDataReady = false; + std::unique_lock lock(mVdMutex); + + while (1) { + if (!rclcpp::ok()) { + DEBUG_VD(" * [threadFunc_videoDepthElab] Ctrl+C received: stopping video depth thread"); + break; + } + if (mThreadStop) { + DEBUG_VD( + " * [threadFunc_videoDepthElab] Video/Depth thread stopped"); + break; + } + + if (!waitForVideoDepthData(lock)) { + break; + } + + handleVideoDepthPublishing(); + + mVdDataReady = false; + } + + DEBUG_STREAM_VD("Video/Depth thread finished"); +} + +// Helper: Setup thread scheduling and debug info +void ZedCamera::setupVideoDepthThread() +{ + if (mChangeThreadSched) { + DEBUG_STREAM_ADV("Video/Depth thread settings"); + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * Default Video/Depth thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + + sched_param par; + par.sched_priority = + (mThreadSchedPolicy == "SCHED_FIFO" || mThreadSchedPolicy == "SCHED_RR") ? + mThreadPrioPointCloud : + 0; + + int sched_policy = SCHED_OTHER; + if (mThreadSchedPolicy == "SCHED_OTHER") { + sched_policy = SCHED_OTHER; + } else if (mThreadSchedPolicy == "SCHED_BATCH") { + sched_policy = SCHED_BATCH; + } else if (mThreadSchedPolicy == "SCHED_FIFO") { + sched_policy = SCHED_FIFO; + } else if (mThreadSchedPolicy == "SCHED_RR") { + sched_policy = SCHED_RR; + } else { + RCLCPP_WARN_STREAM( + get_logger(), + " ! Failed to set thread params! - Policy not supported"); + return; + } + + if (pthread_setschedparam(pthread_self(), sched_policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + + if (_debugAdvanced) { + int policy; + sched_param par2; + if (pthread_getschedparam(pthread_self(), &policy, &par2)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * New Video/Depth thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par2.sched_priority); + } + } + } +} + +// Helper: Wait for video/depth data or thread stop +bool ZedCamera::waitForVideoDepthData(std::unique_lock & lock) +{ + while (!mVdDataReady) { // loop to avoid spurious wakeups + if (mVdDataReadyCondVar.wait_for(lock, std::chrono::milliseconds(500)) == + std::cv_status::timeout) + { + // Check thread stopping + if (!rclcpp::ok()) { + DEBUG_VD("[waitForVideoDepthData] Ctrl+C received: stopping video/depth thread"); + mThreadStop = true; + return false; + } + if (mThreadStop) { + DEBUG_VD( + "[waitForVideoDepthData] Video/Depth thread stopped"); + return false; + } + + DEBUG_VD(" * [waitForVideoDepthData] Waiting for Video/Depth data"); + } + } + DEBUG_VD(" * [waitForVideoDepthData] Video/Depth data ready to be published"); + DEBUG_STREAM_VD( + " * [waitForVideoDepthData] mVdMutex: " << + (lock.owns_lock() ? "Locked" : "Unlocked")); + return true; +} + +// Helper: Handle publishing and frequency control +void ZedCamera::handleVideoDepthPublishing() +{ + rclcpp::Time pub_ts; + publishVideoDepth(pub_ts); + + // ----> Publish sync sensors data if needed + if (mSensCameraSync) { + if (!sl_tools::isZED(mCamRealModel) && mVdPublishing && + pub_ts != TIMEZERO_ROS) + { + publishSensorsData(pub_ts); + } + } + // <---- Publish sync sensors data if needed + + // ----> Check publishing frequency + double vd_period_usec = 1e6 / mVdPubRate; + double elapsed_usec = mVdPubFreqTimer.toc() * 1e6; + + DEBUG_STREAM_VD(" * [handleVideoDepthPublishing] elapsed_usec " << elapsed_usec); + + int wait_usec = 100; + if (elapsed_usec < vd_period_usec) { + wait_usec = static_cast(vd_period_usec - elapsed_usec); + rclcpp::sleep_for(std::chrono::microseconds(wait_usec)); + DEBUG_STREAM_VD(" * [handleVideoDepthPublishing] wait_usec " << wait_usec); + } else { + rclcpp::sleep_for(std::chrono::microseconds(wait_usec)); + } + DEBUG_STREAM_VD(" * [handleVideoDepthPublishing] sleeped for " << wait_usec << " µsec"); + + mVdPubFreqTimer.tic(); + // <---- Check publishing frequency +} + +void ZedCamera::publishCameraInfos() +{ + rclcpp::Time pub_ts = get_clock()->now(); + + publishCameraInfo(mPubRgbCamInfo, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRgbCamInfo, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubLeftCamInfo, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawLeftCamInfo, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubRightCamInfo, mRightCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRightCamInfo, mRightCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubRgbGrayCamInfo, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRgbGrayCamInfo, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubLeftGrayCamInfo, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawLeftGrayCamInfo, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubRightGrayCamInfo, mRightCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRightGrayCamInfo, mRightCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubDepthCamInfo, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubConfMapCamInfo, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRgbCamInfoTrans, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRgbCamInfoTrans, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubLeftCamInfoTrans, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawLeftCamInfoTrans, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubRightCamInfoTrans, mRightCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRightCamInfoTrans, mRightCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubRgbGrayCamInfoTrans, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRgbGrayCamInfoTrans, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubLeftGrayCamInfoTrans, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawLeftGrayCamInfoTrans, mLeftCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubRightGrayCamInfoTrans, mRightCamInfoMsg, pub_ts); + publishCameraInfo(mPubRawRightGrayCamInfoTrans, mRightCamInfoRawMsg, pub_ts); + publishCameraInfo(mPubDepthCamInfoTrans, mLeftCamInfoMsg, pub_ts); + publishCameraInfo(mPubConfMapCamInfoTrans, mLeftCamInfoMsg, pub_ts); +} + +void ZedCamera::setupPointCloudThread() +{ + if (mChangeThreadSched) { + DEBUG_STREAM_ADV("Point Cloud thread settings"); + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * Default Point Cloud thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + + if (mThreadSchedPolicy == "SCHED_OTHER") { + sched_param par; + par.sched_priority = 0; + if (pthread_setschedparam(pthread_self(), SCHED_OTHER, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_BATCH") { + sched_param par; + par.sched_priority = 0; + if (pthread_setschedparam(pthread_self(), SCHED_BATCH, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_FIFO") { + sched_param par; + par.sched_priority = mThreadPrioPointCloud; + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else if (mThreadSchedPolicy == "SCHED_RR") { + sched_param par; + par.sched_priority = mThreadPrioPointCloud; + if (pthread_setschedparam(pthread_self(), SCHED_RR, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + } else { + RCLCPP_WARN_STREAM( + get_logger(), + " ! Failed to set thread params! - Policy not supported"); + } + + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * New Point Cloud thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + } +} + +bool ZedCamera::waitForPointCloudData(std::unique_lock & lock) +{ + while (!mPcDataReady) { // loop to avoid spurious wakeups + if (mPcDataReadyCondVar.wait_for(lock, std::chrono::milliseconds(500)) == + std::cv_status::timeout) + { + // Check thread stopping + if (!rclcpp::ok()) { + DEBUG_PC(" * [waitForPointCloudData] Ctrl+C received: stopping point cloud thread"); + mThreadStop = true; + return false; + } + if (mThreadStop) { + DEBUG_PC( + " * [waitForPointCloudData] Point Cloud thread stopped"); + return false; + } + + DEBUG_PC(" * [waitForPointCloudData] Waiting for point cloud data"); + } + } + DEBUG_PC(" * [waitForPointCloudData] Point Cloud ready to be published"); + DEBUG_STREAM_PC( + " * [waitForPointCloudData] mPcMutex: " << + (lock.owns_lock() ? "Locked" : "Unlocked")); + return true; +} + +void ZedCamera::handlePointCloudPublishing() +{ + publishPointCloud(); + + // ----> Check publishing frequency + double pc_period_usec = 1e6 / mPcPubRate; + + double elapsed_usec = mPcPubFreqTimer.toc() * 1e6; + + DEBUG_STREAM_PC(" * [handlePointCloudPublishing] elapsed_usec " << elapsed_usec); + + int wait_usec = 100; + if (elapsed_usec < pc_period_usec) { + wait_usec = static_cast(pc_period_usec - elapsed_usec); + rclcpp::sleep_for(std::chrono::microseconds(wait_usec)); + DEBUG_STREAM_PC(" * [handlePointCloudPublishing] wait_usec " << wait_usec); + } else { + rclcpp::sleep_for(std::chrono::microseconds(wait_usec)); + } + DEBUG_STREAM_PC(" * [handlePointCloudPublishing] sleeped for " << wait_usec << " µsec"); + + mPcPubFreqTimer.tic(); + // <---- Check publishing frequency + + mPcDataReady = false; +} + +void ZedCamera::threadFunc_pointcloudElab() +{ + DEBUG_STREAM_PC("Point Cloud thread started"); + + // Set the name of the pointcloudElab thread for easier identification in + // system monitors + pthread_setname_np(pthread_self(), (get_name() + std::string("_pointcloudElab")).c_str()); + + setupPointCloudThread(); + + mPcDataReady = false; + + std::unique_lock lock(mPcMutex); + + while (1) { + if (!rclcpp::ok()) { + DEBUG_PC(" * [threadFunc_pointcloudElab] Ctrl+C received: stopping point cloud thread"); + break; + } + if (mThreadStop) { + DEBUG_STREAM_PC( + " * [threadFunc_pointcloudElab] Point Cloud thread stopped"); + break; + } + + if (!waitForPointCloudData(lock)) { + break; + } + + handlePointCloudPublishing(); + } + + DEBUG_STREAM_PC("Pointcloud thread finished"); +} + +bool ZedCamera::handleVideoDepthDynamicParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + DEBUG_VD("handleVideoDepthDynamicParams"); + + // Split handling into smaller helper functions for maintainability + if (sl_tools::isZEDX(mCamRealModel)) { + if (handleGmsl2Params(param, result)) {return true;} + } else { + if (handleUsb3Params(param, result)) {return true;} + } + if (handleCommonVideoParams(param, result)) {return true;} + if (handleDepthParams(param, result)) {return true;} + + // If parameter was not handled, return true (no error, but not handled) + return true; +} + +// Helper for GMSL2 (ZED X) parameters +bool ZedCamera::handleGmsl2Params( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + const std::string & name = param.get_name(); + if (name == "video.exposure_time" || + name == "video.auto_exposure_time_range_min" || + name == "video.auto_exposure_time_range_max" || + name == "video.exposure_compensation" || + name == "video.analog_gain" || + name == "video.auto_analog_gain_range_min" || + name == "video.auto_analog_gain_range_max" || + name == "video.digital_gain" || + name == "video.auto_digital_gain_range_min" || + name == "video.auto_digital_gain_range_max" || + name == "video.denoising") + { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_INTEGER; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + int val = param.as_int(); + if (name == "video.exposure_time") { + mGmslExpTime = val; + mCamAutoExpGain = false; + } else if (name == "video.auto_exposure_time_range_min") { + mGmslAutoExpTimeRangeMin = val; + } else if (name == "video.auto_exposure_time_range_max") { + mGmslAutoExpTimeRangeMax = val; + } else if (name == "video.exposure_compensation") { + mGmslExposureComp = val; + } else if (name == "video.analog_gain") { + mGmslAnalogGain = val; + mCamAutoExpGain = false; + } else if (name == "video.auto_analog_gain_range_min") { + mGmslAnalogGainRangeMin = val; + } else if (name == "video.auto_analog_gain_range_max") { + mGmslAnalogGainRangeMax = val; + } else if (name == "video.digital_gain") { + mGmslDigitalGain = val; + mCamAutoExpGain = false; + } else if (name == "video.auto_digital_gain_range_min") { + mGmslAutoDigitalGainRangeMin = val; + } else if (name == "video.auto_digital_gain_range_max") { + mGmslAutoDigitalGainRangeMax = val; + } else if (name == "video.denoising") { + mGmslDenoising = val; + } + mCamSettingsDirty = true; + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } + return false; +} + +// Helper for USB3 (ZED/ZED2) parameters +bool ZedCamera::handleUsb3Params( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + const std::string & name = param.get_name(); + if (name == "video.brightness" || name == "video.contrast" || name == "video.hue") { + if (sl_tools::isZEDX(mCamRealModel)) { + RCLCPP_WARN_STREAM( + get_logger(), + "Parameter '" << name << "' not available for " << sl::toString(mCamRealModel).c_str()); + return true; + } + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_INTEGER; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + int val = param.as_int(); + if (name == "video.brightness") { + mCamBrightness = val; + } else if (name == "video.contrast") { + mCamContrast = val; + } else if (name == "video.hue") { + mCamHue = val; + } + mCamSettingsDirty = true; + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } + return false; +} + +// Helper for common video parameters +bool ZedCamera::handleCommonVideoParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + const std::string & name = param.get_name(); + if (name == "video.saturation" || name == "video.sharpness" || name == "video.gamma" || + name == "video.exposure" || name == "video.gain" || name == "video.whitebalance_temperature") + { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_INTEGER; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + int val = param.as_int(); + if (name == "video.saturation") { + mCamSaturation = val; + } else if (name == "video.sharpness") { + mCamSharpness = val; + } else if (name == "video.gamma") { + mCamGamma = val; + } else if (name == "video.exposure") { + mCamExposure = val; + mCamAutoExpGain = false; + } else if (name == "video.gain") { + mCamGain = val; + mCamAutoExpGain = false; + } else if (name == "video.whitebalance_temperature") { + mCamWBTemp = val * 100; + mCamAutoWB = false; + } + mCamSettingsDirty = true; + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } else if (name == "video.auto_exposure_gain") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + bool val = param.as_bool(); + if (val != mCamAutoExpGain) { + mTriggerAutoExpGain = true; + } + mCamAutoExpGain = val; + mCamSettingsDirty = true; + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } else if (name == "video.auto_whitebalance") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + bool val = param.as_bool(); + if (val != mCamAutoWB) { + mTriggerAutoWB = true; + } + mCamAutoWB = val; + mCamSettingsDirty = true; + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } else if (name == "general.pub_frame_rate") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + double val = param.as_double(); + if (val < -1.0 || val > mCamGrabFrameRate) { + result.successful = false; + result.reason = name + " must be >= -1 and <= `grab_frame_rate` (0 or -1 = no limit)"; + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + if (val <= 0.0) { + val = static_cast(mCamGrabFrameRate); + } + mVdPubRate = val; + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } + return false; +} + +// Helper for depth-related parameters +bool ZedCamera::handleDepthParams( + const rclcpp::Parameter & param, + rcl_interfaces::msg::SetParametersResult & result) +{ + const std::string & name = param.get_name(); + if (name == "depth.point_cloud_freq") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_DOUBLE; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + double val = param.as_double(); + if (val < -1.0 || val > mCamGrabFrameRate) { + result.successful = false; + result.reason = name + " must be >= -1 and <= `grab_frame_rate` (0 or -1 = no limit)"; + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + if (val <= 0.0) { + val = static_cast(mCamGrabFrameRate); + } + mPcPubRate = val; + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } else if (name == "depth.depth_confidence" || name == "depth.depth_texture_conf") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_INTEGER; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + int val = param.as_int(); + if (name == "depth.depth_confidence") { + mDepthConf = val; + } else if (name == "depth.depth_texture_conf") { + mDepthTextConf = val; + } + + DEBUG_STREAM_DYN_PARAMS("Parameter '" << name << "' correctly set to " << val); + return true; + } else if (name == "depth.remove_saturated_areas") { + rclcpp::ParameterType correctType = rclcpp::ParameterType::PARAMETER_BOOL; + if (param.get_type() != correctType) { + result.successful = false; + result.reason = name + " must be a " + rclcpp::to_string(correctType); + RCLCPP_WARN_STREAM(get_logger(), result.reason); + return true; + } + mRemoveSatAreas = param.as_bool(); + DEBUG_STREAM_DYN_PARAMS( + + "Parameter '" + << name << "' correctly set to " + << (mRemoveSatAreas ? "TRUE" : "FALSE")); + return true; + } + return false; +} + +} // namespace stereolabs diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/include/zed_camera_one_component.hpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/include/zed_camera_one_component.hpp new file mode 100644 index 0000000000..74c79638a1 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/include/zed_camera_one_component.hpp @@ -0,0 +1,549 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ZED_CAMERA_ONE_COMPONENT_HPP_ +#define ZED_CAMERA_ONE_COMPONENT_HPP_ + +#define ENABLE_STREAM_INPUT 1 + +#include +#include + +#include "sl_version.hpp" +#include "sl_tools.hpp" +#include "sl_types.hpp" +#include "visibility_control.hpp" + +namespace stereolabs +{ + +class ZedCameraOne : public rclcpp::Node +{ +public: + ZED_COMPONENTS_PUBLIC + explicit ZedCameraOne(const rclcpp::NodeOptions & options); + + virtual ~ZedCameraOne(); + +protected: + // ----> Initialization functions + void initNode(); + void deInitNode(); + + void initParameters(); + void initServices(); + void initTFCoordFrameNames(); + void initPublishers(); + void initVideoPublishers(); + void initSensorPublishers(); + void initializeTimestamp(); + void initializeDiagnosticStatistics(); + void initThreadsAndTimers(); + + void getSensorsParams(); + void getDebugParams(); + void getVideoParams(); + void getGeneralParams(); + void getTopicEnableParams(); + void getSvoParams(); + void getStreamParams(); + void getCameraModelParams(); + void getCameraInfoParams(); + void getResolutionParams(); + void getOpencvCalibrationParam(); + + void getStreamingServerParams(); + void getAdvancedParams(); + + bool startCamera(); + void closeCamera(); + void createZedObject(); + void logSdkVersion(); + void setupTf2(); + void configureZedInput(); + void setZedInitParams(); + bool openZedCamera(); + void processCameraInformation(); + void setupCameraInfoMessages(); + + void startTempPubTimer(); + void startHeartbeatTimer(); + bool startStreamingServer(); + void stopStreamingServer(); + bool startSvoRecording(std::string & errMsg); + void stopSvoRecording(); + // <---- Initialization functions + + // ----> Utility functions + void fillCamInfo( + sensor_msgs::msg::CameraInfo::SharedPtr camInfoMsg, + const std::string & frameId, bool rawParam = false); + + void applyDynamicSettings(); + void applySaturationSharpnessGamma(); + void applyWhiteBalance(); + void applyExposure(); + void applyAnalogGain(); + void applyDigitalGain(); + void applyExposureCompensationAndDenoising(); + + bool areImageTopicsSubscribed(); + bool areSensorsTopicsSubscribed(); + void retrieveImages(bool gpu); + void publishImages(); + void publishColorImage(const rclcpp::Time & timeStamp); + void publishColorRawImage(const rclcpp::Time & timeStamp); + void publishGrayImage(const rclcpp::Time & timeStamp); + void publishGrayRawImage(const rclcpp::Time & timeStamp); + void publishCameraInfos(); // Used to publish camera infos when no video/depth is subscribed + + void publishImageWithInfo( + const sl::Mat & img, + const image_transport::Publisher & pubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t); +#ifdef FOUND_ISAAC_ROS_NITROS + void publishImageWithInfo( + const sl::Mat & img, + const nitrosImgPub & nitrosPubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t); +#endif + void publishCameraInfo( + const camInfoPub & infoPub, + camInfoMsgPtr & camInfoMsg, const rclcpp::Time & t); + bool publishSensorsData(); + void publishImuFrameAndTopic(); + bool publishSvoStatus(uint64_t frame_ts); + + void updateImuFreqDiagnostics(double dT); + void publishImuMsg(const rclcpp::Time & ts_imu, const sl::SensorsData & sens_data); + void publishImuRawMsg(const rclcpp::Time & ts_imu, const sl::SensorsData & sens_data); + + void publishClock(const sl::Timestamp & ts); + + void updateCaptureDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateInputModeDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateImageDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateSvoDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateTfImuDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateImuDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateTemperatureDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateSvoRecordingDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + void updateStreamingServerDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat); + + void setupGrabThreadPolicy(); + void initializeGrabThreadStatus(); + bool checkGrabThreadInterruption(); + void handleDynamicSettings(); + void updateGrabFrequency(); + bool performCameraGrab(); + void updateFrameTimestamp(); + void publishSvoClock(); + void handleStreamingServer(); + void handleSvoRecordingStatus(); + void handleImageRetrievalAndPublishing(); + + void setupSensorThreadScheduling(); + bool handleSensorThreadInterruption(); + bool waitForCameraOpen(); + bool waitForSensorSubscribers(); + bool handleSensorPublishing(); + void adjustSensorPublishingFrequency(); + + bool handleDynamicVideoParam( + const rclcpp::Parameter & param, const std::string & param_name, + int & count_ok, rcl_interfaces::msg::SetParametersResult & result); + bool handleSaturationSharpnessGamma( + const rclcpp::Parameter & param, + const std::string & param_name, int & count_ok); + bool handleWhiteBalance( + const rclcpp::Parameter & param, const std::string & param_name, + int & count_ok); + bool handleExposure( + const rclcpp::Parameter & param, const std::string & param_name, + int & count_ok); + bool handleAnalogGain( + const rclcpp::Parameter & param, const std::string & param_name, + int & count_ok); + bool handleDigitalGain( + const rclcpp::Parameter & param, const std::string & param_name, + int & count_ok); + // <---- Utility functions + + // ----> Callbacks functions + rcl_interfaces::msg::SetParametersResult callback_dynamicParamChange( + std::vector parameters); + void callback_updateDiagnostic( + diagnostic_updater::DiagnosticStatusWrapper & stat); + void callback_pubTemp(); + void callback_pubHeartbeat(); + + void callback_enableStreaming( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_startSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_stopSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_pauseSvoInput( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + void callback_setSvoFrame( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res); + + // <---- Callbacks functions + + // ----> Thread functions + void threadFunc_zedGrab(); + void threadFunc_pubSensorsData(); + // <---- Threads functions + +private: + // ----> ZED SDK + std::shared_ptr _zed; + sl::InitParametersOne _initParams; + // <---- ZED SDK + + // ----> Threads and Timers + std::thread _grabThread; // Main grab thread + std::thread _sensThread; // Sensors data publish thread + + std::atomic _threadStop; + rclcpp::TimerBase::SharedPtr _initTimer; + rclcpp::TimerBase::SharedPtr _tempPubTimer; // Timer to retrieve and publish camera temperature + rclcpp::TimerBase::SharedPtr _heartbeatTimer; + // <---- Threads and Timers + + // ----> Thread Sync + std::mutex _recMutex; + // <---- Thread Sync + + // ----> Debug variables + bool _debugCommon = false; + bool _debugDynParams = false; + bool _debugVideoDepth = false; + bool _debugSensors = false; + bool _debugCamCtrl = false; + bool _debugStreaming = false; + bool _debugAdvanced = false; + bool _debugNitros = false; + bool _debugTf = false; + // If available, force disable NITROS usage for debugging and testing + // purposes; otherwise, this is always true. + bool _nitrosDisabled = false; + // <---- Debug variables + + // ----> QoS + // https://github.com/ros2/ros2/wiki/About-Quality-of-Service-Settings + rclcpp::QoS _qos; + rclcpp::PublisherOptions _pubOpt; + rclcpp::SubscriptionOptions _subOpt; + // <---- QoS + + // ----> Topics + std::string _topicRoot = "~/"; + std::string _imgColorTopic; + std::string _imgColorRawTopic; + std::string _imgGrayTopic; + std::string _imgRawGrayTopic; + + std::string _sensImuTopic; + std::string _sensImuRawTopic; + std::string _sensTempTopic; + // <---- Topics + + // ----> Publishers + // Image publishers + image_transport::Publisher _pubColorImg; + image_transport::Publisher _pubColorRawImg; + image_transport::Publisher _pubGrayImg; + image_transport::Publisher _pubGrayRawImg; + +#ifdef FOUND_ISAAC_ROS_NITROS + // Nitros image publishers with camera info + nitrosImgPub _nitrosPubColorImg; + nitrosImgPub _nitrosPubColorRawImg; + nitrosImgPub _nitrosPubGrayImg; + nitrosImgPub _nitrosPubGrayRawImg; +#endif + + // Camera Info publishers + camInfoPub _pubColorImgInfo; + camInfoPub _pubColorRawImgInfo; + camInfoPub _pubGrayImgInfo; + camInfoPub _pubGrayRawImgInfo; + camInfoPub _pubColorImgInfoTrans; // `camera_info` topic for the transported image (compressed, theora, nitros, etc) + camInfoPub _pubColorRawImgInfoTrans; // `camera_info` topic for the transported image (compressed, theora, nitros, etc) + camInfoPub _pubGrayImgInfoTrans; // `camera_info` topic for the transported image (compressed, theora, nitros, etc) + camInfoPub _pubGrayRawImgInfoTrans; // `camera_info` topic for the transported image (compressed, theora, nitros, etc) + + // Sensor publishers + imuPub _pubImu; + imuPub _pubImuRaw; + tempPub _pubTemp; + + // Camera-IMU Transform publisher + transfPub _pubCamImuTransf; + + // SVO Clock publisher + clockPub _pubClock; + + // SVO Status publisher + svoStatusPub _pubSvoStatus; + + // Heartbeat Status publisher + heartbeatStatusPub _pubHeartbeatStatus; + // <---- Publishers + + // ----> Publisher variables + bool _usingIPC = false; + sl::Timestamp _lastTs_grab = 0; // Used to calculate stable publish frequency + sl::Timestamp _sdkGrabTS = 0; + std::atomic _colorSubCount; + std::atomic _colorRawSubCount; + std::atomic _graySubCount = 0; + std::atomic _grayRawSubCount = 0; + + std::atomic _imuSubCount; + std::atomic _imuRawSubCount; + double _sensRateComp = 1.0; + + sl::Mat _matColor, _matColorRaw; + sl::Mat _matGray, _matGrayRaw; + // <---- Publisher variables + + // ----> Parameters + std::string _cameraName = "zed_one"; // Name of the camera + int _camGrabFrameRate = 30; // Grab frame rate + sl::RESOLUTION _camResol = sl::RESOLUTION::HD1080; // Default resolution: RESOLUTION_HD1080 + PubRes _pubResolution = PubRes::NATIVE; // Use native grab resolution by default + double _customDownscaleFactor = 1.0; // Used to rescale data with user factor + bool _cameraFlip = false; // Camera flipped? + bool _enableHDR = false; // Enable HDR if supported? + std::string _opencvCalibFile; // Custom OpenCV calibration file + int _sdkVerbose = 0; // SDK verbose level + std::string _sdkVerboseLogFile = ""; // SDK Verbose Log file + int _gpuId = -1; // GPU ID + bool _usePubTimestamps = false; // Use publishing timestamp instead of grab timestamp + bool _grabOnce = false; + bool _grabImuOnce = false; + + int _camSerialNumber = 0; // Camera serial number + int _camId = -1; // Camera ID + + sl::MODEL _camUserModel = sl::MODEL::ZED_XONE_GS; // Default camera model + + //Topic enabler parameters +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + bool _24bitMode = false; +#endif + bool _publishImgRgb = true; + bool _publishImgRaw = false; + bool _publishImgGray = false; + bool _publishSensImu = true; + bool _publishSensImuRaw = false; + bool _publishSensImuTransf = false; + bool _publishSensImuTF = false; + bool _publishSensTemp = false; + + std::string _svoFilepath = ""; +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + std::string _svoDecryptionKey = ""; +#endif + bool _svoLoop = false; + bool _svoRealtime = false; + int _svoFrameStart = 0; + bool _useSvoTimestamp = false; + bool _publishSvoClock = false; + bool _publishStatus = true; + + std::string _streamAddr = ""; // Address for local streaming input + int _streamPort = 10000; + + bool _changeThreadSched = false; + std::string _threadSchedPolicy; + int _threadPrioGrab; + int _threadPrioSens; + + std::atomic _streamingServerRequired; + sl::STREAMING_CODEC _streamingServerCodec = sl::STREAMING_CODEC::H264; + int _streamingServerPort = 30000; + int _streamingServerBitrate = 12500; + int _streamingServerGopSize = -1; + bool _streamingServerAdaptiveBitrate = false; + int _streamingServerChunckSize = 16084; + int _streamingServerTargetFramerate = 0; + + double _sensPubRate = 200.; + // <---- Parameters + + // ----> Dynamic params + OnSetParametersCallbackHandle::SharedPtr _paramChangeCallbackHandle; + + int _camSaturation = 4; + int _camSharpness = 4; + int _camGamma = 8; + bool _camAutoWB = true; + int _camWBTemp = 42; + + bool _camAutoExposure = true; + int _camExpTime = 16666; + int _camAutoExpTimeRangeMin = 28; + int _camAutoExpTimeRangeMax = 30000; + int _camExposureComp = 50; + bool _camAutoAnalogGain = true; + int _camAnalogGain = 8000; + int _camAutoAnalogGainRangeMin = 1000; + int _camAutoAnalogGainRangeMax = 16000; + bool _camAutoDigitalGain = true; + int _camDigitalGain = 128; + int _camAutoDigitalGainRangeMin = 1; + int _camAutoDigitalGainRangeMax = 256; + int _camDenoising = 50; + std::unordered_map _camDynParMapChanged; + // <---- Dynamic params + + // ----> Running status + bool _debugMode = false; // Debug mode active? + bool _svoMode = false; // Input from SVO? + std::atomic _svoPause{false}; // SVO pause status + int _svoFrameId = 0; // Current SVO frame ID + int _svoFrameCount = 0; // Total number of frames in SVO + bool _streamMode = false; // Expecting local streaming data? + + std::atomic _triggerUpdateDynParams; // Trigger auto exposure/gain + + bool _recording = false; + sl::RecordingStatus _recStatus = sl::RecordingStatus(); + + uint64_t _heartbeatCount = 0; + // <---- Running status + + // ----> Timestamps + rclcpp::Time _frameTimestamp; + rclcpp::Time _lastTs_imu; + // <---- Timestamps + + // ----> TF handling + std::unique_ptr _tfBuffer; + std::unique_ptr _tfListener; + std::unique_ptr _tfBroadcaster; + std::unique_ptr _staticTfBroadcaster; + + // Camera IMU transform + sl::Transform _slCamImuTransf; + // <---- TF handling + + // ----> Camera info + sl::MODEL _camRealModel; // Camera model requested to SDK + unsigned int _camFwVersion; // Camera FW version + unsigned int _sensFwVersion; // Sensors FW version + // <---- Camera info + + // ----> Stereolabs Mat Info + int _camWidth; // Camera frame width + int _camHeight; // Camera frame height + sl::Resolution _matResol; + // <---- Stereolabs Mat Info + + // ----> Camera infos + camInfoMsgPtr _camInfoMsg; + camInfoMsgPtr _camInfoRawMsg; + // <---- Camera infos + + // ----> Frame IDs + bool _staticImuTfPublished = false; + std::string _cameraLinkFrameId; + std::string _cameraCenterFrameId; + std::string _camImgFrameId; + std::string _camOptFrameId; + std::string _imuFrameId; + // <---- Frame IDs + + // ----> Diagnostic variables + diagnostic_updater::Updater _diagUpdater; // Diagnostic Updater + + sl_tools::StopWatch _uptimer; + + sl::ERROR_CODE _connStatus = sl::ERROR_CODE::LAST; // Connection status + sl::ERROR_CODE _grabStatus = sl::ERROR_CODE::LAST; // Grab status + float _tempImu = NOT_VALID_TEMP; + uint64_t _frameCount = 0; + uint32_t _svoLoopCount = 0; + + std::unique_ptr _elabPeriodMean_sec; + std::unique_ptr _grabPeriodMean_sec; + std::unique_ptr _imagePeriodMean_sec; + std::unique_ptr _imageElabMean_sec; + std::unique_ptr _imuPeriodMean_sec; + std::unique_ptr _pubImuTF_sec; + std::unique_ptr _pubImu_sec; + bool _imuPublishing = false; + bool _videoPublishing = false; + bool _imageSubscribed = false; + + sl_tools::StopWatch _grabFreqTimer; + sl_tools::StopWatch _imuFreqTimer; + sl_tools::StopWatch _imuTfFreqTimer; + sl_tools::StopWatch _imgPubFreqTimer; + int _sysOverloadCount = 0; + + std::atomic _streamingServerRunning; + // <---- Diagnostic variables + + // ----> SVO Recording parameters + unsigned int _svoRecBitrate = 0; + sl::SVO_COMPRESSION_MODE _svoRecCompression = sl::SVO_COMPRESSION_MODE::H265; + unsigned int _svoRecFramerate = 0; + bool _svoRecTranscode = false; + std::string _svoRecFilename; + // <---- SVO Recording parameters + + // ----> Services + enableStreamingPtr _srvEnableStreaming; + startSvoRecSrvPtr _srvStartSvoRec; + stopSvoRecSrvPtr _srvStopSvoRec; + pauseSvoSrvPtr _srvPauseSvo; + setSvoFramePtr _srvSetSvoFrame; + + sl_tools::StopWatch _setSvoFrameCheckTimer; + // <---- Services + + // ----> Services names + const std::string _srvEnableStreamingName = "enable_streaming"; + const std::string _srvStartSvoRecName = "start_svo_rec"; + const std::string _srvStopSvoRecName = "stop_svo_rec"; + const std::string _srvToggleSvoPauseName = "toggle_svo_pause"; + const std::string _srvSetSvoFrameName = "set_svo_frame"; + // <---- Services names +}; + +} // namespace stereolabs + +#endif // ZED_CAMERA_ONE_COMPONENT_HPP_ diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_main.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_main.cpp new file mode 100644 index 0000000000..3c20540fbb --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_main.cpp @@ -0,0 +1,2605 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zed_camera_one_component.hpp" +#include "sl_logging.hpp" + +#include +#include + +#include + +using namespace std::chrono_literals; +using namespace std::placeholders; + +namespace stereolabs +{ + +ZedCameraOne::ZedCameraOne(const rclcpp::NodeOptions & options) +: Node("zed_node_one", options), + _threadStop(false), + _qos(QOS_QUEUE_SIZE), + _diagUpdater(this), + _grabFreqTimer(get_clock()), + _imuFreqTimer(get_clock()), + _imuTfFreqTimer(get_clock()), + _imgPubFreqTimer(get_clock()), + _frameTimestamp(TIMEZERO_ROS), + _lastTs_imu(TIMEZERO_ROS), + _colorSubCount(0), + _colorRawSubCount(0), + _graySubCount(0), + _grayRawSubCount(0), + _imuSubCount(0), + _imuRawSubCount(0), + _streamingServerRequired(false), + _streamingServerRunning(false), + _triggerUpdateDynParams(true), + _uptimer(get_clock()), + _setSvoFrameCheckTimer(get_clock()) +{ + _usingIPC = options.use_intra_process_comms(); + + RCLCPP_INFO(get_logger(), "================================"); + RCLCPP_INFO(get_logger(), " ZED Camera One Component "); + RCLCPP_INFO(get_logger(), "================================"); + RCLCPP_INFO(get_logger(), " * namespace: %s", get_namespace()); + RCLCPP_INFO(get_logger(), " * node name: %s", get_name()); + RCLCPP_INFO(get_logger(), " * IPC: %s", _usingIPC ? "enabled" : "disabled"); + RCLCPP_INFO(get_logger(), "================================"); + + // Set the name of the main thread for easier identification in + // system monitors + pthread_setname_np( + pthread_self(), + (get_name() + std::string("_main")).c_str()); + + if (((ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < + (SDK_MAJOR_MIN_SUPP * 10 + SDK_MINOR_MIN_SUPP)) || + ((ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) > + (SDK_MAJOR_MAX_SUPP * 10 + SDK_MINOR_MAX_SUPP))) + { + RCLCPP_ERROR_STREAM( + get_logger(), + "This version of the ZED ROS2 wrapper is designed to work with ZED SDK " + "v" << static_cast(SDK_MAJOR_MIN_SUPP) + << "." << static_cast(SDK_MINOR_MIN_SUPP) + << " or newer up to v" << static_cast(SDK_MAJOR_MAX_SUPP) + << "." << static_cast(SDK_MINOR_MAX_SUPP) << "."); + RCLCPP_INFO_STREAM( + get_logger(), "* Detected SDK v" + << ZED_SDK_MAJOR_VERSION << "." + << ZED_SDK_MINOR_VERSION << "." + << ZED_SDK_PATCH_VERSION << "-" + << ZED_SDK_BUILD_ID); + RCLCPP_INFO(get_logger(), "Node stopped. Press Ctrl+C to exit."); + exit(EXIT_FAILURE); + } + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 50 + sl::setEnvironmentVariable("ZED_SDK_DISABLE_PROGRESS_BAR_LOG", "1"); +#endif + +// ----> Publishers/Subscribers options +#ifndef FOUND_FOXY + _pubOpt.qos_overriding_options = + rclcpp::QosOverridingOptions::with_default_policies(); + _subOpt.qos_overriding_options = + rclcpp::QosOverridingOptions::with_default_policies(); +#endif + // <---- Publishers/Subscribers options + + // ----> Start a "one shot timer" to initialize the node + // This is required to make `shared_from_this` available + std::chrono::milliseconds init_msec(static_cast(50.0)); + _initTimer = create_wall_timer( + std::chrono::duration_cast(init_msec), + std::bind(&ZedCameraOne::initNode, this)); + // <---- Start a "one shot timer" to initialize the node +} + +ZedCameraOne::~ZedCameraOne() +{ + deInitNode(); + DEBUG_STREAM_COMM( + "ZED Component destroyed:" << this->get_fully_qualified_name()); +} + +void ZedCameraOne::deInitNode() +{ + DEBUG_STREAM_SENS("Stopping temperatures timer"); + if (_tempPubTimer) { + _tempPubTimer->cancel(); + } + + // ----> Verify that all the threads are not active + DEBUG_STREAM_COMM("Stopping running threads"); + if (!_threadStop) { + _threadStop = true; + } + + DEBUG_STREAM_COMM("Waiting for grab thread..."); + try { + if (_grabThread.joinable()) { + _grabThread.join(); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Grab thread joining exception: " << e.what()); + } + DEBUG_STREAM_COMM("... grab thread stopped"); + + DEBUG_STREAM_COMM("Waiting for sensors thread..."); + try { + if (_sensThread.joinable()) { + _sensThread.join(); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Sensors thread joining exception: " << e.what()); + } + DEBUG_STREAM_COMM("... sensors thread stopped"); + // <---- Verify that all the threads are not active + + // ----> Close the ZED camera + closeCamera(); + // <---- Close the ZED camera +} + +void ZedCameraOne::closeCamera() +{ + if (_zed == nullptr) { + return; + } + + RCLCPP_INFO(get_logger(), "=== CLOSING CAMERA ==="); + _zed->close(); + _zed.reset(); + RCLCPP_INFO(get_logger(), "=== CAMERA CLOSED ==="); +} + +void ZedCameraOne::initParameters() +{ + // DEBUG parameters + getDebugParams(); + + // SVO parameters + getSvoParams(); + + // GENERAL parameters + getGeneralParams(); + + // TOPIC selection parameters + getTopicEnableParams(); + + // Image Parameters + if (!_svoMode) { + getVideoParams(); + } + + // SENSORS parameters + getSensorsParams(); + + // STREAMING SERVER parameters + getStreamingServerParams(); + + // ADVANCED parameters + getAdvancedParams(); +} + +void ZedCameraOne::getGeneralParams() +{ + rclcpp::Parameter paramVal; + RCLCPP_INFO(get_logger(), "=== GENERAL parameters ==="); + + if (!_svoMode) { + getStreamParams(); + } + getCameraModelParams(); + getCameraInfoParams(); + getResolutionParams(); + getOpencvCalibrationParam(); +} + +void ZedCameraOne::getTopicEnableParams() +{ + RCLCPP_INFO(get_logger(), "=== TOPIC selection parameters ==="); + + // General topics + sl_tools::getParam( + shared_from_this(), "general.publish_status", + _publishStatus, _publishStatus, " * Publish Status: "); + + // Image topics +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + sl_tools::getParam( + shared_from_this(), "video.enable_24bit_output", + _24bitMode, _24bitMode); + if (_24bitMode) { + RCLCPP_INFO(get_logger(), " * Image format: BGR 24-bit"); + } else { + RCLCPP_INFO(get_logger(), " * Image format: BGRA 32-bit"); + } +#endif + sl_tools::getParam( + shared_from_this(), "video.publish_rgb", _publishImgRgb, + _publishImgRgb, " * Publish RGB image: "); + sl_tools::getParam( + shared_from_this(), "video.publish_raw", _publishImgRaw, + _publishImgRaw, " * Publish Raw images: "); + sl_tools::getParam( + shared_from_this(), "video.publish_gray", _publishImgGray, + _publishImgGray, " * Publish Gray images: "); + + // Sensor topics + sl_tools::getParam( + shared_from_this(), "sensors.publish_imu", _publishSensImu, + _publishSensImu, " * Publish IMU: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_imu_raw", _publishSensImuRaw, + _publishSensImuRaw, " * Publish IMU Raw: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_cam_imu_transf", _publishSensImuTransf, + _publishSensImuTransf, " * Publish Camera/IMU Transf.: "); + sl_tools::getParam( + shared_from_this(), "sensors.publish_temp", _publishSensTemp, + _publishSensTemp, " * Publish Temperature: "); + +} + +void ZedCameraOne::getSvoParams() +{ + rclcpp::Parameter paramVal; + + RCLCPP_INFO(get_logger(), "=== SVO INPUT parameters ==="); + + sl_tools::getParam( + shared_from_this(), "svo.svo_path", std::string(), + _svoFilepath); + if (_svoFilepath.compare("live") == 0) { + _svoFilepath = ""; + } + + if (_svoFilepath == "") { + _svoMode = false; + } else { + RCLCPP_INFO_STREAM( + get_logger(), + " * SVO: '" << _svoFilepath.c_str() << "'"); + _svoMode = true; + sl_tools::getParam( + shared_from_this(), "svo.use_svo_timestamps", + _useSvoTimestamp, _useSvoTimestamp, + " * Use SVO timestamp: "); + if (_useSvoTimestamp) { + sl_tools::getParam( + shared_from_this(), "svo.publish_svo_clock", + _publishSvoClock, _publishSvoClock, + " * Publish SVO timestamp: "); + } + + sl_tools::getParam(shared_from_this(), "svo.svo_loop", _svoLoop, _svoLoop); + if (_useSvoTimestamp) { + if (_svoLoop) { + RCLCPP_WARN( + get_logger(), + "SVO Loop is not supported when using SVO timestamps. Loop " + "playback disabled."); + _svoLoop = false; + } + RCLCPP_INFO_STREAM( + get_logger(), + " * SVO Loop: " << (_svoLoop ? "TRUE" : "FALSE")); + } + sl_tools::getParam( + shared_from_this(), "svo.svo_realtime", _svoRealtime, + _svoRealtime, " * SVO Realtime: "); + + sl_tools::getParam( + shared_from_this(), "svo.play_from_frame", + _svoFrameStart, _svoFrameStart, + " * SVO start frame: ", false, 0); + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + sl_tools::getParam( + shared_from_this(), "svo.decryption_key", std::string(), + _svoDecryptionKey); +#endif + } +} + +void ZedCameraOne::getStreamParams() +{ + _streamMode = false; + if (!_svoMode) { + sl_tools::getParam(shared_from_this(), "stream.stream_address", std::string(), _streamAddr); + if (_streamAddr != "") { +#if ENABLE_STREAM_INPUT + _streamMode = true; + sl_tools::getParam(shared_from_this(), "stream.stream_port", _streamPort, _streamPort); + RCLCPP_INFO_STREAM( + get_logger(), " * Local stream input: " << _streamAddr << ":" << _streamPort); +#else + RCLCPP_ERROR_STREAM( + get_logger(), + "Local stream input is not enabled in this version. This feature will be available later"); + exit(EXIT_FAILURE); +#endif + } + } +} + +void ZedCameraOne::getCameraModelParams() +{ + std::string camera_model = "zed"; + sl_tools::getParam(shared_from_this(), "general.camera_model", camera_model, camera_model); + if (camera_model == "zedxonegs") { + _camUserModel = sl::MODEL::ZED_XONE_GS; + if (_svoMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing an SVO for " << sl::toString( + _camUserModel) << " camera model."); + } else if (_streamMode) { + RCLCPP_INFO_STREAM( + get_logger(), + " + Playing a network stream from a " << sl::toString(_camUserModel) << " camera model."); + } else if (!IS_JETSON) { + RCLCPP_ERROR_STREAM( + get_logger(), "Camera model " << sl::toString( + _camUserModel).c_str() << " is available only with NVIDIA Jetson devices."); + exit(EXIT_FAILURE); + } + } else if (camera_model == "zedxone4k") { + _camUserModel = sl::MODEL::ZED_XONE_UHD; + if (_svoMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing an SVO for " << sl::toString( + _camUserModel) << " camera model."); + } else if (_streamMode) { + RCLCPP_INFO_STREAM( + get_logger(), + " + Playing a network stream from a " << sl::toString(_camUserModel) << " camera model."); + } else if (!IS_JETSON) { + RCLCPP_ERROR_STREAM( + get_logger(), "Camera model " << sl::toString( + _camUserModel).c_str() << " is available only with NVIDIA Jetson devices."); + exit(EXIT_FAILURE); + } + } else if (camera_model == "zedxonehdr") { + _camUserModel = sl::MODEL::ZED_XONE_HDR; + if (_svoMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing an SVO for " + << sl::toString(_camUserModel) + << " camera model."); + } else if (_streamMode) { + RCLCPP_INFO_STREAM( + get_logger(), " + Playing a network stream from a " + << sl::toString(_camUserModel) + << " camera model."); + } else if (!IS_JETSON) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Camera model " << sl::toString(_camUserModel).c_str() + << " is available only with NVIDIA Jetson devices."); + exit(EXIT_FAILURE); + } + } else { + RCLCPP_ERROR_STREAM( + get_logger(), + "Camera model not valid in parameter values: " << camera_model); + } + RCLCPP_INFO_STREAM(get_logger(), " * Camera model: " << camera_model << " - " << _camUserModel); +} + +void ZedCameraOne::getCameraInfoParams() +{ + sl_tools::getParam( + shared_from_this(), "general.camera_name", _cameraName, _cameraName, " * Camera name: "); + if (!_svoMode) { + sl_tools::getParam( + shared_from_this(), "general.serial_number", _camSerialNumber, _camSerialNumber, + " * Camera SN: "); + sl_tools::getParam(shared_from_this(), "general.camera_id", _camId, _camId, " * Camera ID: "); + sl_tools::getParam( + shared_from_this(), "general.grab_frame_rate", _camGrabFrameRate, _camGrabFrameRate, " * Camera framerate: ", false, 15, + 120); + } + sl_tools::getParam( + shared_from_this(), "general.gpu_id", _gpuId, _gpuId, " * GPU ID: ", false, -1, 256); +} + +void ZedCameraOne::getResolutionParams() +{ + if (!_svoMode) { + std::string resol = "AUTO"; + sl_tools::getParam(shared_from_this(), "general.grab_resolution", resol, resol); + if (resol == "AUTO") { + _camResol = sl::RESOLUTION::AUTO; + } else if (resol == "HD4K" && _camUserModel == sl::MODEL::ZED_XONE_UHD) { + _camResol = sl::RESOLUTION::HD4K; + } else if (resol == "QHDPLUS" && _camUserModel == sl::MODEL::ZED_XONE_UHD) { + _camResol = sl::RESOLUTION::QHDPLUS; + } else if (resol == "HD1536" && _camUserModel == sl::MODEL::ZED_XONE_HDR) { + _camResol = sl::RESOLUTION::HD1536; +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + } else if (resol == "XVGA" && _camUserModel == sl::MODEL::ZED_XONE_HDR) { + _camResol = sl::RESOLUTION::XVGA; +#endif + } else if (resol == "HD1200" && _camUserModel != sl::MODEL::ZED_XONE_HDR) { + _camResol = sl::RESOLUTION::HD1200; + } else if (resol == "HD1080" && _camUserModel != sl::MODEL::ZED_XONE_HDR) { + _camResol = sl::RESOLUTION::HD1080; + } else if (resol == "SVGA" && _camUserModel != sl::MODEL::ZED_XONE_HDR) { + _camResol = sl::RESOLUTION::SVGA; + } else { + RCLCPP_WARN( + get_logger(), "Not valid 'general.grab_resolution' value: '%s'. Using 'AUTO' setting.", + resol.c_str()); + _camResol = sl::RESOLUTION::AUTO; + } + RCLCPP_INFO_STREAM(get_logger(), " * Camera resolution: " << sl::toString(_camResol).c_str()); + } + + std::string out_resol = "NATIVE"; + sl_tools::getParam(shared_from_this(), "general.pub_resolution", out_resol, out_resol); + if (out_resol == "NATIVE") { + _pubResolution = PubRes::NATIVE; + } else if (out_resol == "CUSTOM") { + _pubResolution = PubRes::CUSTOM; + } else { + RCLCPP_WARN( + get_logger(), "Not valid 'general.pub_resolution' value: '%s'. Using default setting instead.", + out_resol.c_str()); + out_resol = "NATIVE"; + _pubResolution = PubRes::NATIVE; + } + RCLCPP_INFO_STREAM(get_logger(), " * Publishing resolution: " << out_resol.c_str()); + + if (_pubResolution == PubRes::CUSTOM) { + sl_tools::getParam( + shared_from_this(), "general.pub_downscale_factor", _customDownscaleFactor, _customDownscaleFactor, " * Publishing downscale factor: ", false, 1.0, + 5.0); + } else { + _customDownscaleFactor = 1.0; + } +} + +void ZedCameraOne::getOpencvCalibrationParam() +{ + sl_tools::getParam( + shared_from_this(), "general.optional_opencv_calibration_file", _opencvCalibFile, _opencvCalibFile, + " * OpenCV custom calibration: "); +} + +void ZedCameraOne::getStreamingServerParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== STREAMING SERVER parameters ==="); + + bool stream_server = false; + sl_tools::getParam( + shared_from_this(), "stream_server.stream_enabled", + stream_server, stream_server, " * Stream enabled: "); + _streamingServerRequired = stream_server; + + std::string codec = "H264"; + sl_tools::getParam(shared_from_this(), "stream_server.codec", codec, codec); + if (codec == "H264") { + _streamingServerCodec = sl::STREAMING_CODEC::H264; + RCLCPP_INFO(get_logger(), " * Stream codec: H264"); + } else if (codec == "H265") { + _streamingServerCodec = sl::STREAMING_CODEC::H265; + RCLCPP_INFO(get_logger(), " * Stream codec: H265"); + } else { + _streamingServerCodec = sl::STREAMING_CODEC::H264; + RCLCPP_WARN_STREAM( + get_logger(), + "Invalid value for the parameter 'stream_server.codec': " << codec << + ". Using the default value."); + RCLCPP_INFO(get_logger(), " * Stream codec: H264"); + } + + sl_tools::getParam( + shared_from_this(), "stream_server.port", + _streamingServerPort, _streamingServerPort, + " * Stream port:", false, 1024, 65535); + sl_tools::getParam( + shared_from_this(), "stream_server.bitrate", + _streamingServerBitrate, _streamingServerBitrate, + " * Stream bitrate:", false, 1000, 60000); + sl_tools::getParam( + shared_from_this(), "stream_server.gop_size", + _streamingServerGopSize, _streamingServerGopSize, + " * Stream GOP size:", false, -1, 256); + sl_tools::getParam( + shared_from_this(), "stream_server.chunk_size", + _streamingServerChunckSize, _streamingServerChunckSize, + " * Stream Chunk size:", false, 1024, 65000); + sl_tools::getParam( + shared_from_this(), "stream_server.adaptative_bitrate", + _streamingServerAdaptiveBitrate, + _streamingServerAdaptiveBitrate, " * Adaptative bitrate:"); + sl_tools::getParam( + shared_from_this(), "stream_server.target_framerate", + _streamingServerTargetFramerate, + _streamingServerTargetFramerate, " * Target frame rate:"); +} + +void ZedCameraOne::getAdvancedParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== ADVANCED parameters ==="); + + sl_tools::getParam( + shared_from_this(), "advanced.change_thread_priority", + _changeThreadSched, _changeThreadSched, + " * Change thread priority: "); + + if (_changeThreadSched) { + sl_tools::getParam( + shared_from_this(), "advanced.thread_sched_policy", + _threadSchedPolicy, _threadSchedPolicy, + " * Thread sched. policy: "); + + if (_threadSchedPolicy == "SCHED_FIFO" || _threadSchedPolicy == "SCHED_RR") { + if (!sl_tools::checkRoot()) { + RCLCPP_WARN_STREAM( + get_logger(), + "'sudo' permissions required to set " + << _threadSchedPolicy + << " thread scheduling policy. Using Linux " + "default [SCHED_OTHER]"); + _threadSchedPolicy = "SCHED_OTHER"; + } else { + sl_tools::getParam( + shared_from_this(), "advanced.thread_grab_priority", + _threadPrioGrab, _threadPrioGrab, + " * Grab thread priority: "); + sl_tools::getParam( + shared_from_this(), "advanced.thread_sensor_priority", + _threadPrioSens, _threadPrioSens, + " * Sensors thread priority: "); + } + } + } +} + +void ZedCameraOne::getDebugParams() +{ + rclcpp::Parameter paramVal; + + RCLCPP_INFO(get_logger(), "=== DEBUG parameters ==="); + + sl_tools::getParam( + shared_from_this(), "debug.sdk_verbose", _sdkVerbose, + _sdkVerbose, " * SDK Verbose: ", false, 0, 1000); + sl_tools::getParam( + shared_from_this(), "debug.sdk_verbose_log_file", + _sdkVerboseLogFile, _sdkVerboseLogFile, + " * SDK Verbose File: "); + sl_tools::getParam( + shared_from_this(), "debug.use_pub_timestamps", + _usePubTimestamps, _usePubTimestamps, + " * Use Pub Timestamps: "); + + sl_tools::getParam( + shared_from_this(), "debug.debug_common", _debugCommon, + _debugCommon, " * Debug Common: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_dyn_params", + _debugDynParams, _debugDynParams, + " * Debug Dynamic Parameters: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_video_depth", + _debugVideoDepth, _debugVideoDepth, + " * Debug Image/Depth: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_camera_controls", + _debugCamCtrl, _debugCamCtrl, + " * Debug Camera Controls: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_sensors", _debugSensors, + _debugSensors, " * Debug Sensors: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_streaming", + _debugStreaming, _debugStreaming, " * Debug Streaming: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_advanced", _debugAdvanced, + _debugAdvanced, " * Debug Advanced: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_tf", _debugTf, _debugTf, + " * Debug TF: "); + sl_tools::getParam( + shared_from_this(), "debug.debug_nitros", _debugNitros, + _debugNitros, " * Debug Nitros: "); + + // Set debug mode + + _debugMode = _debugCommon || _debugDynParams || _debugVideoDepth || + _debugCamCtrl || _debugSensors || _debugStreaming || + _debugAdvanced || _debugTf || _debugNitros; + + if (_debugMode) { + rcutils_ret_t res = rcutils_logging_set_logger_level( + get_logger().get_name(), RCUTILS_LOG_SEVERITY_DEBUG); + + if (res != RCUTILS_RET_OK) { + RCLCPP_INFO(get_logger(), "Error setting DEBUG level for logger"); + } else { + RCLCPP_INFO(get_logger(), " + Debug Mode enabled +"); + } + } else { + rcutils_ret_t res = rcutils_logging_set_logger_level( + get_logger().get_name(), RCUTILS_LOG_SEVERITY_INFO); + + if (res != RCUTILS_RET_OK) { + RCLCPP_INFO(get_logger(), "Error setting INFO level for logger"); + } + } + + DEBUG_STREAM_COMM( + "[ROS2] Using RMW_IMPLEMENTATION " + << rmw_get_implementation_identifier()); + + const char * nitrosReason = "not_available"; + +#ifdef FOUND_ISAAC_ROS_NITROS + nitrosReason = "enabled"; + + sl_tools::getParam( + shared_from_this(), "debug.disable_nitros", + _nitrosDisabled, _nitrosDisabled); + + bool nitrosDisabledByParam = _nitrosDisabled; + + if (nitrosDisabledByParam) { + nitrosReason = "param_debug.disable_nitros"; + } + + if (!_nitrosDisabled && _usingIPC) { + RCLCPP_WARN( + get_logger(), + "NITROS transport is incompatible with ROS 2 Intra-Process Communication " + "(IPC). NITROS will be disabled. To use NITROS, launch with " + "enable_ipc:=false. NITROS provides its own zero-copy transport, " + "so disabling IPC does not reduce performance."); + _nitrosDisabled = true; + nitrosReason = "auto_disabled_ipc_incompatibility"; + } + + if (nitrosDisabledByParam) { + RCLCPP_WARN( + get_logger(), + "NITROS is available, but is disabled by 'debug.disable_nitros'"); + } +#else + _nitrosDisabled = true; // Force disable NITROS if not available +#endif + + RCLCPP_DEBUG( + get_logger(), + "Transport summary: IPC=%s, NITROS=%s, reason=%s", + _usingIPC ? "enabled" : "disabled", + _nitrosDisabled ? "disabled" : "enabled", + nitrosReason); +} + +void ZedCameraOne::initNode() +{ + // Stop the timer for "one shot" initialization + _initTimer->cancel(); + + // ----> Diagnostic initialization + std::string info = sl::toString(_camUserModel).c_str(); + _diagUpdater.add( + info, this, + &ZedCameraOne::callback_updateDiagnostic); + std::string hw_id = std::string("Stereolabs camera: ") + _cameraName; + _diagUpdater.setHardwareID(hw_id); + // <---- Diagnostic initialization + + // Parameters initialization + initParameters(); + + // Services initialization + initServices(); + + // ----> Start camera + if (!startCamera()) { + _zed.reset(); + exit(EXIT_FAILURE); + } + // <---- Start camera + + // Callback when the node is destroyed + // This is used to stop the camera when the node is destroyed + // and to stop the timers + + // Close camera callback before shutdown + using rclcpp::contexts::get_global_default_context; + get_global_default_context()->add_pre_shutdown_callback( + [this]() { + DEBUG_COMM("ZED X One Component is shutting down"); + deInitNode(); + DEBUG_COMM("ZED X One Component is shutting down - done"); + }); + + // Dynamic parameters callback + _paramChangeCallbackHandle = add_on_set_parameters_callback( + std::bind(&ZedCameraOne::callback_dynamicParamChange, this, _1)); +} + +void ZedCameraOne::initServices() +{ + RCLCPP_INFO(get_logger(), "=== SERVICES ==="); + + std::string srv_name; + std::string srv_prefix = "~/"; + + // Enable Streaming + srv_name = srv_prefix + _srvEnableStreamingName; + _srvEnableStreaming = create_service( + srv_name, + std::bind(&ZedCameraOne::callback_enableStreaming, this, _1, _2, _3)); + RCLCPP_INFO(get_logger(), " * '%s'", _srvEnableStreaming->get_service_name()); + + // Start SVO Recording + srv_name = srv_prefix + _srvStartSvoRecName; + _srvStartSvoRec = create_service( + srv_name, std::bind(&ZedCameraOne::callback_startSvoRec, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << _srvStartSvoRec->get_service_name() + << "'"); + // Stop SVO Recording + srv_name = srv_prefix + _srvStopSvoRecName; + _srvStopSvoRec = create_service( + srv_name, std::bind(&ZedCameraOne::callback_stopSvoRec, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << _srvStopSvoRec->get_service_name() + << "'"); + + // Pause SVO (only if the realtime playing mode is disabled) + if (_svoMode) { +#ifndef USE_SVO_REALTIME_PAUSE + if (!_svoRealtime) { +#endif + srv_name = srv_prefix + _srvToggleSvoPauseName; + _srvPauseSvo = create_service( + srv_name, + std::bind(&ZedCameraOne::callback_pauseSvoInput, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << _srvPauseSvo->get_service_name() + << "'"); +#ifndef USE_SVO_REALTIME_PAUSE + } +#endif + // Set Service for SVO frame + srv_name = srv_prefix + _srvSetSvoFrameName; + _srvSetSvoFrame = create_service( + srv_name, std::bind(&ZedCameraOne::callback_setSvoFrame, this, _1, _2, _3)); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on service: '" + << _srvSetSvoFrame->get_service_name() + << "'"); + } +} + +bool ZedCameraOne::startCamera() +{ + RCLCPP_INFO(get_logger(), "=== STARTING CAMERA ==="); + + createZedObject(); + logSdkVersion(); + setupTf2(); + configureZedInput(); + setZedInitParams(); + + if (!openZedCamera()) { + return false; + } + + _uptimer.tic(); + + // ----> Set SVO first frame if required + if (_svoMode && _svoFrameStart != 0) { + int svo_frames = _zed->getSVONumberOfFrames(); + + if (_svoFrameStart > svo_frames) { + RCLCPP_ERROR_STREAM( + get_logger(), + "The SVO contains " + << svo_frames + << " frames. The requested starting frame (" + << _svoFrameStart << ") is invalid."); + return false; + } + + _zed->setSVOPosition(_svoFrameStart); + RCLCPP_WARN_STREAM( + get_logger(), + "SVO playing from frame #" << _svoFrameStart); + } + // <---- Set SVO first frame if required + + processCameraInformation(); + initTFCoordFrameNames(); + setupCameraInfoMessages(); + initPublishers(); + initializeTimestamp(); + initializeDiagnosticStatistics(); + initThreadsAndTimers(); + + return true; +} + +// Helper functions for startCamera() + +void ZedCameraOne::createZedObject() +{ + _zed = std::make_shared(); +} + +void ZedCameraOne::logSdkVersion() +{ + RCLCPP_INFO( + get_logger(), "ZED SDK Version: %d.%d.%d - Build %s", + ZED_SDK_MAJOR_VERSION, ZED_SDK_MINOR_VERSION, + ZED_SDK_PATCH_VERSION, ZED_SDK_BUILD_ID); +} + +void ZedCameraOne::setupTf2() +{ + _tfBuffer = std::make_unique(get_clock()); + _tfListener = std::make_unique(*_tfBuffer); + _tfBroadcaster = std::make_unique(this); + + _staticImuTfPublished = false; + if (!_usingIPC) { + _staticTfBroadcaster = std::make_unique(this); + } else { // Cannot use TRANSIENT_LOCAL with intra-process comms + _staticTfBroadcaster.reset(); + } +} + +void ZedCameraOne::configureZedInput() +{ + + if (!_svoFilepath.empty()) { + RCLCPP_INFO(get_logger(), "=== SVO OPENING ==="); + _initParams.input.setFromSVOFile(_svoFilepath.c_str()); + _initParams.svo_real_time_mode = _svoRealtime; +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 53 + _initParams.svo_decryption_key = _svoDecryptionKey.c_str(); +#endif + _svoMode = true; + return; + } + + if (!_streamAddr.empty()) { + RCLCPP_INFO(get_logger(), "=== LOCAL STREAMING OPENING ==="); + _initParams.input.setFromStream( + _streamAddr.c_str(), + static_cast(_streamPort)); + _streamMode = true; + return; + } + RCLCPP_INFO(get_logger(), "=== CAMERA OPENING ==="); + _initParams.camera_fps = _camGrabFrameRate; + _initParams.camera_resolution = static_cast(_camResol); + + if (_camSerialNumber > 0) { +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51 + _initParams.input.setFromSerialNumber(_camSerialNumber, sl::BUS_TYPE::GMSL); +#else + _initParams.input.setFromSerialNumber(_camSerialNumber); +#endif + } else if (_camId >= 0) { +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) < 51 + _initParams.input.setFromCameraID(_camId, sl::BUS_TYPE::GMSL, sl::CAMERA_TYPE::MONO); +#else + _initParams.input.setFromCameraID(_camId, sl::BUS_TYPE::GMSL); +#endif + } +} + +void ZedCameraOne::setZedInitParams() +{ + _initParams.async_grab_camera_recovery = true; + _initParams.camera_image_flip = (_cameraFlip ? sl::FLIP_MODE::ON : sl::FLIP_MODE::OFF); + _initParams.coordinate_system = ROS_COORDINATE_SYSTEM; + _initParams.coordinate_units = ROS_MEAS_UNITS; + _initParams.enable_hdr = _enableHDR; + if (!_opencvCalibFile.empty()) { + _initParams.optional_opencv_calibration_file = _opencvCalibFile.c_str(); + } + _initParams.sdk_verbose = _sdkVerbose; + _initParams.sdk_verbose_log_file = _sdkVerboseLogFile.c_str(); +} + +bool ZedCameraOne::openZedCamera() +{ + _grabStatus = sl::ERROR_CODE::LAST; + _connStatus = _zed->open(_initParams); + + if (_connStatus != sl::ERROR_CODE::SUCCESS) { + +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + if (_connStatus == sl::ERROR_CODE::DRIVER_FAILURE) { + RCLCPP_ERROR_STREAM( + get_logger(), + "ZED X Driver failure: " << sl::toVerbose(_connStatus) + << ". Please verify that the ZED drivers " + "are correctly installed."); + return false; + } +#endif + + if (_connStatus == sl::ERROR_CODE::INVALID_CALIBRATION_FILE) { + if (_opencvCalibFile.empty()) { + RCLCPP_ERROR_STREAM( + get_logger(), "Calibration file error: " + << sl::toVerbose(_connStatus)); + } else { + RCLCPP_ERROR_STREAM( + get_logger(), + "If you are using a custom OpenCV calibration file, please check " + "the correctness of the path of the calibration file " + "in the parameter 'general.optional_opencv_calibration_file': '" + << _opencvCalibFile << "'."); + RCLCPP_ERROR( + get_logger(), + "If the file exists, it may contain invalid information."); + } + return false; + } else if (_svoMode) { + RCLCPP_WARN( + get_logger(), "Error opening SVO: %s", + sl::toString(_connStatus).c_str()); + return false; + } else if (_streamMode) { + RCLCPP_WARN( + get_logger(), "Error opening Local Stream: %s", + sl::toString(_connStatus).c_str()); + return false; + } else { + RCLCPP_WARN( + get_logger(), "Error opening camera: %s", + sl::toString(_connStatus).c_str()); + RCLCPP_INFO(get_logger(), "Please verify the camera connection"); + return false; + } + } else { + DEBUG_STREAM_COMM("Opening successfull"); + } + return true; +} + +void ZedCameraOne::processCameraInformation() +{ + sl::CameraOneInformation camInfo = _zed->getCameraInformation(); + + float realFps = camInfo.camera_configuration.fps; + if (realFps != static_cast(_camGrabFrameRate)) { + RCLCPP_WARN_STREAM( + get_logger(), + "!!! `general.grab_frame_rate` value is not valid: '" + << _camGrabFrameRate + << "'. Automatically replaced with '" << realFps + << "'. Please fix the parameter !!!"); + _camGrabFrameRate = realFps; + } + + cuCtxGetDevice(&_gpuId); + RCLCPP_INFO_STREAM(get_logger(), "ZED SDK running on GPU #" << _gpuId); + + _camRealModel = camInfo.camera_model; + + if (_camRealModel != _camUserModel) { + RCLCPP_WARN(get_logger(), "Camera model does not match user parameter."); + + if (_camRealModel == sl::MODEL::ZED_XONE_GS) { + RCLCPP_WARN(get_logger(), "Please set the parameter 'general.camera_model' to 'zedxonegs'"); + } else if (_camRealModel == sl::MODEL::ZED_XONE_UHD) { + RCLCPP_WARN(get_logger(), "Please set the parameter 'general.camera_model' to 'zedxone4k'"); + } else if (_camRealModel == sl::MODEL::ZED_XONE_HDR) { + RCLCPP_WARN(get_logger(), "Please set the parameter 'general.camera_model' to 'zedxonehdr'"); + } + } + + RCLCPP_INFO_STREAM( + get_logger(), " * Camera Model -> " + << sl::toString(_camRealModel).c_str()); + _camSerialNumber = camInfo.serial_number; + RCLCPP_INFO_STREAM(get_logger(), " * Serial Number -> " << _camSerialNumber); + + // ----> Update HW ID + std::string hw_id = std::string("Stereolabs "); + hw_id += sl::toString(_camRealModel).c_str(); + hw_id += " - '" + _cameraName + "'" + " - S/N: " + std::to_string(_camSerialNumber); + _diagUpdater.setHardwareID(hw_id); + _diagUpdater.force_update(); + // <---- Update HW ID + + RCLCPP_INFO_STREAM( + get_logger(), + " * Focal Lenght -> " + << camInfo.camera_configuration.calibration_parameters.focal_length_metric + << " mm"); + + RCLCPP_INFO_STREAM( + get_logger(), + " * Input\t -> " + << sl::toString(camInfo.input_type).c_str()); + + if (_svoMode) { + RCLCPP_INFO( + get_logger(), " * SVO resolution\t-> %dx%d", + camInfo.camera_configuration.resolution.width, + camInfo.camera_configuration.resolution.height); + RCLCPP_INFO_STREAM( + get_logger(), + " * SVO framerate\t\t-> " + << (camInfo.camera_configuration.fps)); + } + + if (!_svoMode) { + _camFwVersion = camInfo.camera_configuration.firmware_version; + RCLCPP_INFO_STREAM( + get_logger(), + " * Camera FW Version -> " << _camFwVersion); + _sensFwVersion = camInfo.sensors_configuration.firmware_version; + RCLCPP_INFO_STREAM( + get_logger(), + " * Sensors FW Version -> " << _sensFwVersion); + } + + _slCamImuTransf = camInfo.sensors_configuration.camera_imu_transform; + DEBUG_SENS("Camera-IMU Transform:\n%s", _slCamImuTransf.getInfos().c_str()); + + _camWidth = camInfo.camera_configuration.resolution.width; + _camHeight = camInfo.camera_configuration.resolution.height; + + RCLCPP_INFO_STREAM( + get_logger(), " * Camera grab frame size -> " + << _camWidth << "x" << _camHeight); + + int pub_w, pub_h; + pub_w = static_cast(std::round(_camWidth / _customDownscaleFactor)); + pub_h = static_cast(std::round(_camHeight / _customDownscaleFactor)); + + if (pub_w > _camWidth || pub_h > _camHeight) { + RCLCPP_WARN_STREAM( + get_logger(), "The publishing resolution (" + << pub_w << "x" << pub_h + << ") cannot be higher than the grabbing resolution (" + << _camWidth << "x" << _camHeight + << "). Using grab resolution for output messages."); + pub_w = _camWidth; + pub_h = _camHeight; + } + + _matResol = sl::Resolution(pub_w, pub_h); + RCLCPP_INFO_STREAM( + get_logger(), " * Publishing frame size -> " + << _matResol.width << "x" + << _matResol.height); +} + +void ZedCameraOne::initializeTimestamp() +{ + if (_svoMode) { + if (_useSvoTimestamp) { + _frameTimestamp = sl_tools::slTime2Ros(_zed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } else { + _frameTimestamp = + sl_tools::slTime2Ros(_zed->getTimestamp(sl::TIME_REFERENCE::CURRENT)); + } + } else { + _frameTimestamp = + sl_tools::slTime2Ros(_zed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } +} + +void ZedCameraOne::initializeDiagnosticStatistics() +{ + _elabPeriodMean_sec = std::make_unique(_camGrabFrameRate); + _grabPeriodMean_sec = std::make_unique(_camGrabFrameRate); + _imagePeriodMean_sec = std::make_unique(_camGrabFrameRate); + _imageElabMean_sec = std::make_unique(_camGrabFrameRate); + _imuPeriodMean_sec = std::make_unique(20); + _pubImuTF_sec = std::make_unique(_sensPubRate); + _pubImu_sec = std::make_unique(_sensPubRate); +} + +void ZedCameraOne::initThreadsAndTimers() +{ + // Start Heartbeat timer + startHeartbeatTimer(); + + // ----> Start CMOS Temperatures thread + startTempPubTimer(); + // <---- Start CMOS Temperatures thread + + // Start sensor thread + _sensThread = std::thread(&ZedCameraOne::threadFunc_pubSensorsData, this); + + // Start grab thread + _grabThread = std::thread(&ZedCameraOne::threadFunc_zedGrab, this); +} + +void ZedCameraOne::callback_updateDiagnostic( + diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + DEBUG_COMM("=== Update Diagnostic ==="); + + if (_connStatus != sl::ERROR_CODE::SUCCESS) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::ERROR, + sl::toString(_connStatus).c_str()); + return; + } + + stat.addf("Uptime", "%s", sl_tools::seconds2str(_uptimer.toc()).c_str()); + + if (_grabStatus == sl::ERROR_CODE::SUCCESS) { + updateCaptureDiagnostics(stat); + updateInputModeDiagnostics(stat); + updateImageDiagnostics(stat); + updateSvoDiagnostics(stat); + updateTfImuDiagnostics(stat); + } else if (_grabStatus == sl::ERROR_CODE::LAST) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::OK, + "Camera initializing"); + } else { + stat.summaryf( + diagnostic_msgs::msg::DiagnosticStatus::ERROR, + "%s", sl::toString(_grabStatus).c_str()); + } + + updateImuDiagnostics(stat); + updateTemperatureDiagnostics(stat); + updateSvoRecordingDiagnostics(stat); + updateStreamingServerDiagnostics(stat); +} + +// --- Helper functions for diagnostics --- + +void ZedCameraOne::updateCaptureDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + double freq = 1. / _grabPeriodMean_sec->getAvg(); + double freq_perc = 100. * freq / _camGrabFrameRate; + stat.addf("Capture", "Mean Frequency: %.1f Hz (%.1f%%)", freq, freq_perc); + + double frame_proc_sec = _elabPeriodMean_sec->getAvg(); + double frame_grab_period = 1. / _camGrabFrameRate; + stat.addf( + "Capture", "Tot. Processing Time: %.6f sec (Max. %.3f sec)", + frame_proc_sec, frame_grab_period); + + if (frame_proc_sec > frame_grab_period) { + _sysOverloadCount++; + } + + if (_sysOverloadCount >= 10) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "System overloaded. Consider reducing " + "'general.grab_frame_rate' or 'general.grab_resolution'"); + } else { + _sysOverloadCount = 0; + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::OK, + "Camera grabbing"); + } + + // ----> Frame drop count + if (_zed && _zed->isOpened()) { + auto dropped = _zed->getFrameDroppedCount(); + uint64_t total = dropped + _frameCount; + auto perc_drop = 100. * static_cast(dropped) / total; + stat.addf( + "Frame Drop rate", "%u/%lu (%g%%)", + dropped, total, perc_drop); + } + // <---- Frame drop count +} + +void ZedCameraOne::updateInputModeDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + + if (_svoMode) { + stat.add("Input mode", "SVO"); + stat.addf("SVO file", "%s", _svoFilepath.c_str()); + return; + } + + if (_streamMode) { + stat.add("Input mode", "LOCAL STREAM"); + } else { + stat.add("Input mode", "Live Camera"); + } +} + +void ZedCameraOne::updateImageDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + if (_videoPublishing) { + double freq = 1. / _imagePeriodMean_sec->getAvg(); + double freq_perc = 100. * freq / _camGrabFrameRate; + double frame_grab_period = 1. / _camGrabFrameRate; + stat.addf("Image", "Mean Frequency: %.1f Hz (%.1f%%)", freq, freq_perc); + stat.addf( + "Image", "Processing Time: %.6f sec (Max. %.3f sec)", + _imagePeriodMean_sec->getAvg(), frame_grab_period); + } else { + stat.add("Image", "Topic not subscribed"); + } +} + +void ZedCameraOne::updateSvoDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + if (_svoMode) { + double svo_perc = + 100. * (static_cast(_svoFrameId) / _svoFrameCount); + + stat.addf( + "Playing SVO", "%sFrame: %d/%d (%.1f%%)", + (_svoPause ? "PAUSED - " : ""), _svoFrameId, _svoFrameCount, + svo_perc); + stat.addf("SVO Loop", "%s", (_svoLoop ? "ON" : "OFF")); + if (_svoLoop) { + stat.addf("SVO Loop Count", "%d", _svoLoopCount); + } + stat.addf("SVO Real Time mode", "%s", (_svoRealtime ? "ON" : "OFF")); + } +} + +void ZedCameraOne::updateTfImuDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + if (_publishSensImuTF) { + double freq = 1. / _pubImuTF_sec->getAvg(); + stat.addf("TF IMU", "Mean Frequency: %.1f Hz", freq); + } else { + stat.add("TF IMU", "DISABLED"); + } +} + +void ZedCameraOne::updateImuDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + if (_imuPublishing) { + double freq = 1. / _pubImu_sec->getAvg(); + stat.addf("IMU", "Mean Frequency: %.1f Hz", freq); + } else { + stat.add("IMU Sensor", "Topics not subscribed"); + } +} + +void ZedCameraOne::updateTemperatureDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + stat.addf("Camera Temp.", "%.1f °C", _tempImu); + + if (_tempImu > 70.f) { + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "High Camera temperature"); + } +} + +void ZedCameraOne::updateSvoRecordingDiagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + if (_recording) { + if (!_recStatus.status) { + stat.add("SVO Recording", "ERROR"); + stat.summary( + diagnostic_msgs::msg::DiagnosticStatus::WARN, + "Error adding frames to SVO file while recording. " + "Check " + "free disk space"); + } else { + stat.add("SVO Recording", "ACTIVE"); + stat.addf( + "SVO compression time", "%g msec", + _recStatus.average_compression_time); + stat.addf( + "SVO compression ratio", "%.1f%%", + _recStatus.average_compression_ratio); + stat.addf("SVO Frame Encoded", "%d", _recStatus.number_frames_encoded); + stat.addf("SVO Frame Ingested", "%d", _recStatus.number_frames_ingested); + } + } else { + stat.add("SVO Recording", "NOT ACTIVE"); + } +} + +void ZedCameraOne::updateStreamingServerDiagnostics( + diagnostic_updater::DiagnosticStatusWrapper & stat) +{ + if (_streamingServerRunning) { + stat.add("Streaming Server", "ACTIVE"); + + sl::StreamingParameters params; + params = _zed->getStreamingParameters(); + + stat.addf("Streaming port", "%d", static_cast(params.port)); + stat.addf( + "Streaming codec", "%s", + (params.codec == sl::STREAMING_CODEC::H264 ? "H264" : "H265")); + stat.addf("Streaming bitrate", "%d mbps", static_cast(params.bitrate)); + stat.addf("Streaming chunk size", "%d B", static_cast(params.chunk_size)); + stat.addf("Streaming GOP size", "%d", static_cast(params.gop_size)); + } else { + stat.add("Streaming Server", "NOT ACTIVE"); + } +} + +rcl_interfaces::msg::SetParametersResult +ZedCameraOne::callback_dynamicParamChange( + std::vector parameters) +{ + DEBUG_STREAM_COMM("=== Parameter change callback ==="); + + rcl_interfaces::msg::SetParametersResult result; + result.successful = true; + + int count_ok = 0; + int count = 0; + + DEBUG_STREAM_COMM("Modifying " << parameters.size() << " parameters"); + + for (const auto & param : parameters) { + DEBUG_STREAM_COMM("Param #" << count << ": " << param.get_name()); + count++; + + std::string param_name = param.get_name(); + + if (param_name == "sensors.sensors_pub_rate") { + double value = param.as_double(); + if (value != _sensPubRate) { + _sensPubRate = value; + _pubImuTF_sec->setNewSize(static_cast(_sensPubRate)); + _pubImu_sec->setNewSize(static_cast(_sensPubRate)); + DEBUG_STREAM_COMM(" * " << param_name << " changed to " << value); + } else { + DEBUG_STREAM_COMM(" * " << param_name << " not changed: " << value); + } + continue; + } + + auto found = _camDynParMapChanged.find(param_name); + if (found != _camDynParMapChanged.end()) { + if (handleDynamicVideoParam(param, param_name, count_ok, result)) { + continue; + } else { + result.successful = false; + result.reason = "Parameter " + param_name + " not mapped"; + DEBUG_COMM(result.reason.c_str()); + break; + } + } else { + result.successful = false; + result.reason = "Parameter " + param_name + " not recognized"; + DEBUG_COMM(result.reason.c_str()); + break; + } + } + + DEBUG_STREAM_COMM("Updated parameters: " << count_ok << "/" << parameters.size()); + + _triggerUpdateDynParams = (count_ok > 0); + + if (count_ok > 0) { + if (_debugCommon) { + DEBUG_COMM("Settings to be applied: "); + for (auto & param: _camDynParMapChanged) { + if (param.second) {DEBUG_STREAM_COMM(" * " << param.first);} + } + } + } + + return result; +} + +// Helper function for handling dynamic video parameters +bool ZedCameraOne::handleDynamicVideoParam( + const rclcpp::Parameter & param, + const std::string & param_name, + int & count_ok, + rcl_interfaces::msg::SetParametersResult & result) +{ + if (handleSaturationSharpnessGamma(param, param_name, count_ok)) { + result.successful = true; + return true; + } + if (handleWhiteBalance(param, param_name, count_ok)) { + result.successful = true; + return true; + } + if (handleExposure(param, param_name, count_ok)) { + result.successful = true; + return true; + } + if (handleAnalogGain(param, param_name, count_ok)) { + result.successful = true; + return true; + } + if (handleDigitalGain(param, param_name, count_ok)) { + result.successful = true; + return true; + } + return false; +} + +// Helper for saturation, sharpness, gamma +bool ZedCameraOne::handleSaturationSharpnessGamma( + const rclcpp::Parameter & param, const std::string & param_name, int & count_ok) +{ + auto updateIntParam = [this](const std::string & paramName, const int value, int & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + + if (param_name == "video.saturation") { + if (updateIntParam(param_name, param.as_int(), _camSaturation)) {count_ok++;} + return true; + } else if (param_name == "video.sharpness") { + if (updateIntParam(param_name, param.as_int(), _camSharpness)) {count_ok++;} + return true; + } else if (param_name == "video.gamma") { + if (updateIntParam(param_name, param.as_int(), _camGamma)) {count_ok++;} + return true; + } + return false; +} + +// Helper for white balance +bool ZedCameraOne::handleWhiteBalance( + const rclcpp::Parameter & param, const std::string & param_name, int & count_ok) +{ + auto updateIntParam = [this](const std::string & paramName, const int value, int & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + auto updateBoolParam = [this](const std::string & paramName, const bool value, bool & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + + if (param_name == "video.auto_whitebalance") { + if (updateBoolParam(param_name, param.as_bool(), _camAutoWB)) {count_ok++;} + return true; + } else if (param_name == "video.whitebalance_temperature") { + if (updateIntParam(param_name, param.as_int(), _camWBTemp)) { + count_ok++; + updateBoolParam("video.auto_whitebalance", false, _camAutoWB); + } + return true; + } + return false; +} + +// Helper for exposure +bool ZedCameraOne::handleExposure( + const rclcpp::Parameter & param, const std::string & param_name, int & count_ok) +{ + auto updateIntParam = [this](const std::string & paramName, const int value, int & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + auto updateBoolParam = [this](const std::string & paramName, const bool value, bool & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + + if (param_name == "video.auto_exposure") { + if (updateBoolParam(param_name, param.as_bool(), _camAutoExposure)) {count_ok++;} + return true; + } else if (param_name == "video.exposure_compensation") { + if (updateIntParam(param_name, param.as_int(), _camExposureComp)) {count_ok++;} + return true; + } else if (param_name == "video.exposure_time") { + if (updateIntParam(param_name, param.as_int(), _camExpTime)) { + count_ok++; + updateBoolParam("video.auto_exposure", false, _camAutoExposure); + updateIntParam("video.auto_exposure_time_range_min", _camExpTime, _camAutoExpTimeRangeMin); + updateIntParam("video.auto_exposure_time_range_max", _camExpTime, _camAutoExpTimeRangeMax); + } + return true; + } else if (param_name == "video.auto_exposure_time_range_min") { + if (updateIntParam(param_name, param.as_int(), _camAutoExpTimeRangeMin)) { + count_ok++; + if (_camAutoExpTimeRangeMin != _camAutoExpTimeRangeMax) { + updateBoolParam("video.auto_exposure", true, _camAutoExposure); + } else { + updateBoolParam("video.auto_exposure", false, _camAutoExposure); + updateIntParam("video.exposure_time", _camAutoExpTimeRangeMin, _camExpTime); + } + } + return true; + } else if (param_name == "video.auto_exposure_time_range_max") { + if (updateIntParam(param_name, param.as_int(), _camAutoExpTimeRangeMax)) { + count_ok++; + if (_camAutoExpTimeRangeMin != _camAutoExpTimeRangeMax) { + updateBoolParam("video.auto_exposure", true, _camAutoExposure); + } else { + updateBoolParam("video.auto_exposure", false, _camAutoExposure); + updateIntParam("video.exposure_time", _camAutoExpTimeRangeMax, _camExpTime); + } + } + return true; + } + return false; +} + +// Helper for analog gain +bool ZedCameraOne::handleAnalogGain( + const rclcpp::Parameter & param, const std::string & param_name, int & count_ok) +{ + auto updateIntParam = [this](const std::string & paramName, const int value, int & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + auto updateBoolParam = [this](const std::string & paramName, const bool value, bool & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + + if (param_name == "video.auto_analog_gain") { + if (updateBoolParam(param_name, param.as_bool(), _camAutoAnalogGain)) {count_ok++;} + return true; + } else if (param_name == "video.analog_gain") { + if (updateIntParam(param_name, param.as_int(), _camAnalogGain)) { + count_ok++; + updateBoolParam("video.auto_analog_gain", false, _camAutoAnalogGain); + updateIntParam( + "video.auto_analog_gain_range_min", _camAnalogGain, + _camAutoAnalogGainRangeMin); + updateIntParam( + "video.auto_analog_gain_range_max", _camAnalogGain, + _camAutoAnalogGainRangeMax); + } + return true; + } else if (param_name == "video.auto_analog_gain_range_min") { + if (updateIntParam(param_name, param.as_int(), _camAutoAnalogGainRangeMin)) { + count_ok++; + if (_camAutoAnalogGainRangeMin != _camAutoAnalogGainRangeMax) { + updateBoolParam("video.auto_analog_gain", true, _camAutoAnalogGain); + } else { + updateBoolParam("video.auto_analog_gain", false, _camAutoAnalogGain); + updateIntParam("video.analog_gain", _camAutoAnalogGainRangeMin, _camAnalogGain); + } + } + return true; + } else if (param_name == "video.auto_analog_gain_range_max") { + if (updateIntParam(param_name, param.as_int(), _camAutoAnalogGainRangeMax)) { + count_ok++; + if (_camAutoAnalogGainRangeMin != _camAutoAnalogGainRangeMax) { + updateBoolParam("video.auto_analog_gain", true, _camAutoAnalogGain); + } else { + updateBoolParam("video.auto_analog_gain", false, _camAutoAnalogGain); + updateIntParam("video.analog_gain", _camAutoAnalogGainRangeMax, _camAnalogGain); + } + } + return true; + } + return false; +} + +// Helper for digital gain +bool ZedCameraOne::handleDigitalGain( + const rclcpp::Parameter & param, const std::string & param_name, int & count_ok) +{ + auto updateIntParam = [this](const std::string & paramName, const int value, int & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + auto updateBoolParam = [this](const std::string & paramName, const bool value, bool & paramVal) { + if (value != paramVal) { + paramVal = value; + _camDynParMapChanged[paramName] = true; + DEBUG_STREAM_COMM(" * " << paramName << " changed to " << value); + } else { + _camDynParMapChanged[paramName] = false; + DEBUG_STREAM_COMM(" * " << paramName << " not changed: " << value); + } + return _camDynParMapChanged[paramName]; + }; + + if (param_name == "video.auto_digital_gain") { + if (updateBoolParam(param_name, param.as_bool(), _camAutoDigitalGain)) {count_ok++;} + return true; + } else if (param_name == "video.digital_gain") { + if (updateIntParam(param_name, param.as_int(), _camDigitalGain)) { + count_ok++; + updateBoolParam("video.auto_digital_gain", false, _camAutoDigitalGain); + updateIntParam( + "video.auto_digital_gain_range_min", _camDigitalGain, + _camAutoDigitalGainRangeMin); + updateIntParam( + "video.auto_digital_gain_range_max", _camDigitalGain, + _camAutoDigitalGainRangeMax); + } + return true; + } else if (param_name == "video.auto_digital_gain_range_min") { + if (updateIntParam(param_name, param.as_int(), _camAutoDigitalGainRangeMin)) { + count_ok++; + if (_camAutoDigitalGainRangeMin != _camAutoDigitalGainRangeMax) { + updateBoolParam("video.auto_digital_gain", true, _camAutoDigitalGain); + } else { + updateBoolParam("video.auto_digital_gain", false, _camAutoDigitalGain); + updateIntParam("video.digital_gain", _camAutoDigitalGainRangeMin, _camDigitalGain); + } + } + return true; + } else if (param_name == "video.auto_digital_gain_range_max") { + if (updateIntParam(param_name, param.as_int(), _camAutoDigitalGainRangeMax)) { + count_ok++; + if (_camAutoDigitalGainRangeMin != _camAutoDigitalGainRangeMax) { + updateBoolParam("video.auto_digital_gain", true, _camAutoDigitalGain); + } else { + updateBoolParam("video.auto_digital_gain", false, _camAutoDigitalGain); + updateIntParam("video.digital_gain", _camAutoDigitalGainRangeMax, _camDigitalGain); + } + } + return true; + } + return false; +} + +void ZedCameraOne::initTFCoordFrameNames() +{ + // ----> Coordinate frames + _cameraLinkFrameId = _cameraName + "_camera_link"; + _cameraCenterFrameId = _cameraName + "_camera_center"; + _camImgFrameId = _cameraName + "_camera_frame"; + _camOptFrameId = _cameraName + "_camera_frame_optical"; + _imuFrameId = _cameraName + "_imu_link"; + + // Print TF frames + RCLCPP_INFO_STREAM(get_logger(), "=== TF FRAMES ==="); + RCLCPP_INFO_STREAM(get_logger(), " * Camera link\t-> " << _cameraLinkFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Camera center\t-> " << _cameraCenterFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Image\t\t-> " << _camImgFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * Optical\t-> " << _camOptFrameId); + RCLCPP_INFO_STREAM(get_logger(), " * IMU\t\t-> " << _imuFrameId); + // <---- Coordinate frames +} + +void ZedCameraOne::initPublishers() +{ + RCLCPP_INFO(get_logger(), "=== PUBLISHED TOPICS ==="); + + // Video + initVideoPublishers(); + + // Sensors + initSensorPublishers(); + + // ----> Camera/imu transform message + if (_publishSensImuTransf) { + std::string cam_imu_tr_topic = _topicRoot + "left_cam_imu_transform"; + auto qos = _qos; + if (!_usingIPC) { + // Use TRANSIENT_LOCAL durability if not using intra-process comms + qos = qos.durability(rclcpp::DurabilityPolicy::TransientLocal); + } + _pubCamImuTransf = create_publisher( + cam_imu_tr_topic, qos, _pubOpt); + + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << _pubCamImuTransf->get_topic_name()); + + sl::Orientation sl_rot = _slCamImuTransf.getOrientation(); + sl::Translation sl_tr = _slCamImuTransf.getTranslation(); + RCLCPP_INFO( + get_logger(), " * Camera-IMU Translation: \n %g %g %g", sl_tr.x, + sl_tr.y, sl_tr.z); + RCLCPP_INFO( + get_logger(), " * Camera-IMU Rotation:\n%s", + sl_rot.getRotationMatrix().getInfos().c_str()); + } + // <---- Camera/imu transform message + + // Status topic names + std::string status_root = _topicRoot + "status/"; + std::string svo_status_topic = status_root + "svo"; + std::string heartbeat_topic = status_root + "heartbeat"; + + RCLCPP_INFO(get_logger(), " +++ STATUS TOPICS +++"); + + // ----> SVO Status publisher + if (_svoMode) { + if (_publishStatus) { + _pubSvoStatus = create_publisher( + svo_status_topic, _qos, _pubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << _pubSvoStatus->get_topic_name()); + } + if (_useSvoTimestamp && _publishSvoClock) { + auto clock_qos = rclcpp::ClockQoS(); + clock_qos.reliability(rclcpp::ReliabilityPolicy::Reliable); // REQUIRED + _pubClock = create_publisher( + "/clock", clock_qos, _pubOpt); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << _pubClock->get_topic_name()); + } + } + // <---- SVO Status publisher + + if (_publishStatus) { + // ----> Heartbeat Status publisher + _pubHeartbeatStatus = create_publisher( + heartbeat_topic, _qos, _pubOpt); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << _pubHeartbeatStatus->get_topic_name()); + // <---- Heartbeat Status publisher + } +} + +void ZedCameraOne::threadFunc_zedGrab() +{ + DEBUG_STREAM_COMM("Grab thread started"); + + // Set the name of the zedGrab thread for easier identification in + // system monitors + pthread_setname_np(pthread_self(), (get_name() + std::string("_zedGrab")).c_str()); + + setupGrabThreadPolicy(); + + initializeGrabThreadStatus(); + + while (1) { + try { + RCLCPP_INFO_STREAM_ONCE(get_logger(), "=== " << _cameraName << " started ==="); + + sl_tools::StopWatch grabElabTimer(get_clock()); + + if (checkGrabThreadInterruption()) {break;} + + if (_svoMode && _svoPause) { + if (!_grabOnce) { + rclcpp::sleep_for(100ms); +#ifdef USE_SVO_REALTIME_PAUSE + // Dummy grab + mZed->grab(); +#endif + continue; + } else { + _grabOnce = false; // Reset the flag and grab once + } + } + + handleDynamicSettings(); + + updateGrabFrequency(); + + if (!_svoPause) { + grabElabTimer.tic(); + if (!performCameraGrab()) {break;} + updateFrameTimestamp(); + if (_svoMode) { + _svoFrameId = _zed->getSVOPosition(); + _svoFrameCount = _zed->getSVONumberOfFrames(); + + publishSvoClock(); + } + handleStreamingServer(); + } + + handleSvoRecordingStatus(); + + handleImageRetrievalAndPublishing(); + + _elabPeriodMean_sec->addValue(grabElabTimer.toc()); + } catch (rclcpp::exceptions::ParameterNotDeclaredException & ex) { + RCLCPP_ERROR_STREAM(get_logger(), "ParameterNotDeclaredException: " << ex.what()); + continue; + } catch (const std::exception & e) { + RCLCPP_ERROR_STREAM(get_logger(), "Exception: " << e.what()); + continue; + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("threadFunc_zedGrab: Generic exception."); + continue; + } + } + + _diagUpdater.broadcast(diagnostic_msgs::msg::DiagnosticStatus::STALE, "Grab thread stopped"); + _diagUpdater.force_update(); + + // Stop the heartbeat + _heartbeatTimer->cancel(); + + DEBUG_STREAM_COMM("Grab thread finished"); +} + +// Helper functions for threadFunc_zedGrab + +void ZedCameraOne::setupGrabThreadPolicy() +{ + if (_changeThreadSched) { + DEBUG_STREAM_ADV("Grab thread settings"); + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * Default GRAB thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + + sched_param par; + par.sched_priority = + (_threadSchedPolicy == "SCHED_FIFO" || _threadSchedPolicy == "SCHED_RR") ? + _threadPrioGrab : + 0; + int policy = SCHED_OTHER; + if (_threadSchedPolicy == "SCHED_BATCH") { + policy = SCHED_BATCH; + } else if (_threadSchedPolicy == "SCHED_FIFO") { + policy = SCHED_FIFO; + } else if (_threadSchedPolicy == "SCHED_RR") { + policy = SCHED_RR; + } + if (pthread_setschedparam(pthread_self(), policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + + if (_debugAdvanced) { + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * New GRAB thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + } +} + +void ZedCameraOne::initializeGrabThreadStatus() +{ + _frameCount = 0; + _threadStop = false; +} + +bool ZedCameraOne::checkGrabThreadInterruption() +{ + if (!rclcpp::ok()) { + DEBUG_STREAM_COMM("Ctrl+C received: stopping grab thread"); + _threadStop = true; + return true; + } + if (_threadStop) { + DEBUG_STREAM_COMM("Grab thread stopped"); + return true; + } + return false; +} + +void ZedCameraOne::handleDynamicSettings() +{ + if (!_svoMode && _triggerUpdateDynParams) { + applyDynamicSettings(); + } +} + +void ZedCameraOne::updateGrabFrequency() +{ + double elapsed_sec = _grabFreqTimer.toc(); + _grabPeriodMean_sec->addValue(elapsed_sec); + _grabFreqTimer.tic(); +} + +bool ZedCameraOne::performCameraGrab() +{ + _grabStatus = _zed->grab(); + if (_grabStatus != sl::ERROR_CODE::SUCCESS) { + if (_svoMode && _grabStatus == sl::ERROR_CODE::END_OF_SVOFILE_REACHED) { + // ----> Check SVO status + if (_svoLoop) { + _svoLoopCount++; + _zed->setSVOPosition(_svoFrameStart); + RCLCPP_WARN_STREAM( + get_logger(), + "SVO reached the end and it has been restarted from frame #" + << _svoFrameStart); + rclcpp::sleep_for( + std::chrono::microseconds( + static_cast(_grabPeriodMean_sec->getAvg() * 1e6))); + return true; + } else { + // ----> Stop all the other threads and Timers + _threadStop = true; + if (_tempPubTimer) { + _tempPubTimer->cancel(); + } + // <---- Stop all the other threads and Timers + + RCLCPP_WARN(get_logger(), "SVO reached the end."); + + // Force SVO status update + if (!publishSvoStatus(_frameTimestamp.nanoseconds())) { + RCLCPP_WARN(get_logger(), "Node stopped. Press Ctrl+C to exit."); + return false; + } else { + if (_pubSvoStatus) { + RCLCPP_WARN_STREAM( + get_logger(), + "Waiting for SVO status subscribers to " + "unsubscribe. Active subscribers: " + << _pubSvoStatus->get_subscription_count()); + } + _diagUpdater.force_update(); + rclcpp::sleep_for(1s); + return true; + } + } + //<---- Check SVO status + } else if (_grabStatus == sl::ERROR_CODE::CAMERA_REBOOTING) { + RCLCPP_ERROR_STREAM( + get_logger(), "Connection issue detected: " << sl::toString( + _grabStatus).c_str()); + rclcpp::sleep_for(1s); + return true; + } else if (_grabStatus == sl::ERROR_CODE::CAMERA_NOT_INITIALIZED || + _grabStatus == sl::ERROR_CODE::FAILURE) + { + RCLCPP_ERROR_STREAM( + get_logger(), "Camera issue detected: " + << sl::toString(_grabStatus).c_str() << ". " << sl::toVerbose(_grabStatus).c_str() + << ". Trying to recover the connection..."); + rclcpp::sleep_for(1s); + return true; + } else { + RCLCPP_ERROR_STREAM( + get_logger(), "Critical camera error: " + << sl::toString(_grabStatus).c_str() << ". " << sl::toVerbose(_grabStatus).c_str() + << ". NODE KILLED."); + _zed.reset(); + exit(EXIT_FAILURE); + } + } + _frameCount++; + return true; +} + +void ZedCameraOne::updateFrameTimestamp() +{ + _sdkGrabTS = _zed->getTimestamp(sl::TIME_REFERENCE::IMAGE); + + if (_svoMode) { + if (_useSvoTimestamp) { + _frameTimestamp = sl_tools::slTime2Ros(_sdkGrabTS); + } else { + _frameTimestamp = sl_tools::slTime2Ros(_zed->getTimestamp(sl::TIME_REFERENCE::CURRENT)); + } + } else { + _frameTimestamp = sl_tools::slTime2Ros(_sdkGrabTS); + } +} + +void ZedCameraOne::publishSvoClock() +{ + if (_svoMode) { + // ----> Publish Clock if required + if (_useSvoTimestamp && _publishSvoClock) { + publishClock(_zed->getTimestamp(sl::TIME_REFERENCE::IMAGE)); + } + // <---- Publish Clock if required + } +} + +void ZedCameraOne::publishClock(const sl::Timestamp & ts) +{ + DEBUG_COMM("Publishing clock"); + + if (!_pubClock) { + return; + } + + size_t subCount = 0; + try { + subCount = _pubClock->get_subscription_count(); + } catch (...) { + rcutils_reset_error(); + DEBUG_COMM("publishClock: Exception while counting subscribers"); + return; + } + + if (subCount == 0) { + return; + } + + auto msg = std::make_unique(); + msg->clock = sl_tools::slTime2Ros(ts); + + if (_pubClock) { + _pubClock->publish(std::move(msg)); + } +} + +bool ZedCameraOne::publishSvoStatus(uint64_t frame_ts) +{ + if (!_svoMode) { + return false; + } + + if (!_pubSvoStatus) { + return false; + } + + size_t subCount = 0; + try { + subCount = _pubSvoStatus->get_subscription_count(); + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("publishSvoStatus: Exception while counting subscribers"); + return false; + } + + if (subCount > 0) { + auto msg = std::make_unique(); + + // ----> Fill the status message + msg->file_name = _svoFilepath; + msg->frame_id = _zed->getSVOPosition(); + msg->total_frames = _zed->getSVONumberOfFrames(); + msg->frame_ts = frame_ts; + + if (_svoPause) { + msg->status = zed_msgs::msg::SvoStatus::STATUS_PAUSED; + } else if (_grabStatus == sl::ERROR_CODE::END_OF_SVOFILE_REACHED) { + msg->frame_id = msg->total_frames - 1; + msg->status = zed_msgs::msg::SvoStatus::STATUS_END; + } else { + msg->status = zed_msgs::msg::SvoStatus::STATUS_PLAYING; + } + + msg->loop_active = _svoLoop; + msg->loop_count = _svoLoopCount; + msg->real_time_mode = _svoRealtime; + // <---- Fill the status message + + // Publish the message + if (_pubSvoStatus) { + _pubSvoStatus->publish(std::move(msg)); + } + return true; + } + return false; +} + +void ZedCameraOne::callback_pubHeartbeat() +{ + if (!_pubHeartbeatStatus) { + return; + } + + if (!_publishStatus) { + return; + } + + if (_threadStop) { + return; + } + + // ----> Count the subscribers + size_t sub_count = 0; + try { + sub_count = _pubHeartbeatStatus->get_subscription_count(); + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("publishHeartbeat: Exception while counting subscribers"); + return; + } + + if (sub_count == 0) { + return; + } + // <---- Count the subscribers + + // ----> Fill the message + auto msg = std::make_unique(); + msg->beat_count = ++_heartbeatCount; + msg->camera_sn = _camSerialNumber; + msg->full_name = this->get_fully_qualified_name(); + msg->node_name = this->get_name(); + msg->node_ns = this->get_namespace(); + msg->simul_mode = false; //mSimMode; + msg->svo_mode = _svoMode; + // <---- Fill the message + + // Publish the heartbeat + if (_pubHeartbeatStatus) { + _pubHeartbeatStatus->publish(std::move(msg)); + } +} + +void ZedCameraOne::handleStreamingServer() +{ + if (_streamingServerRequired && !_streamingServerRunning) { + DEBUG_STR("Streaming server required, but not running"); + startStreamingServer(); + } +} + +void ZedCameraOne::handleSvoRecordingStatus() +{ + { + std::lock_guard lock(_recMutex); + if (_recording) { + _recStatus = _zed->getRecordingStatus(); + if (!_recStatus.status) { + rclcpp::Clock steady_clock(RCL_STEADY_TIME); + RCLCPP_WARN_THROTTLE(get_logger(), steady_clock, 1000.0, "Error saving frame to SVO"); + } + } + } +} + +bool ZedCameraOne::startStreamingServer() +{ + DEBUG_STR("Starting streaming server"); + + if (_zed->isStreamingEnabled()) { + _zed->disableStreaming(); + RCLCPP_WARN(get_logger(), "A streaming server was already running and has been stopped"); + } + + sl::StreamingParameters params; + params.adaptative_bitrate = _streamingServerAdaptiveBitrate; + params.bitrate = _streamingServerBitrate; + params.chunk_size = _streamingServerChunckSize; + params.codec = _streamingServerCodec; + params.gop_size = _streamingServerGopSize; + params.port = _streamingServerPort; + params.target_framerate = _streamingServerTargetFramerate; + + sl::ERROR_CODE res; + res = _zed->enableStreaming(params); + if (res != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), "Error starting the Streaming server: " << sl::toString( + res) << " - " << sl::toVerbose(res)); + _streamingServerRunning = false; + } else { + _streamingServerRunning = true; + RCLCPP_INFO(get_logger(), "Streaming server started"); + } + return _streamingServerRunning; +} + +void ZedCameraOne::stopStreamingServer() +{ + if (_zed->isStreamingEnabled()) { + _zed->disableStreaming(); + RCLCPP_INFO(get_logger(), "Streaming server stopped"); + } else { + RCLCPP_WARN(get_logger(), "A streaming server was not enabled."); + } + + _streamingServerRunning = false; + _streamingServerRequired = false; +} + + +void ZedCameraOne::callback_enableStreaming( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + if (req->data) { + if (_streamingServerRunning) { + RCLCPP_WARN(get_logger(), "A Streaming Server is already running"); + res->message = "A Streaming Server is already running"; + res->success = false; + return; + } + // Start + if (startStreamingServer()) { + res->message = "Streaming Server started"; + res->success = true; + return; + } else { + res->message = + "Error occurred starting the Streaming Server. Read the log for more " + "info"; + res->success = false; + return; + } + } else { + // Stop + if (!_streamingServerRunning) { + RCLCPP_WARN( + get_logger(), + "There is no Streaming Server active to be stopped"); + res->message = "There is no Streaming Server active to be stopped"; + res->success = false; + return; + } + + RCLCPP_INFO(get_logger(), "Stopping the Streaming Server"); + stopStreamingServer(); + + res->message = "Streaming Server stopped"; + res->success = true; + return; + } +} + +void ZedCameraOne::callback_startSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Start SVO Recording service called **"); + + if (_svoMode) { + RCLCPP_WARN( + get_logger(), + "Cannot start SVO recording while playing SVO as input"); + res->message = "Cannot start SVO recording while playing SVO as input"; + res->success = false; + return; + } + + std::lock_guard lock(_recMutex); + + if (_recording) { + RCLCPP_WARN(get_logger(), "SVO Recording is already enabled"); + res->message = "SVO Recording is already enabled"; + res->success = false; + return; + } + + _svoRecBitrate = req->bitrate; + if ((_svoRecBitrate != 0) && + ((_svoRecBitrate < 1000) || (_svoRecBitrate > 60000))) + { + RCLCPP_WARN( + get_logger(), + "'bitrate' value not valid. Please use a value " + "in range [1000,60000], or 0 for default"); + res->message = + "'bitrate' value not valid. Please use a value in range " + "[1000,60000], or 0 for default"; + res->success = false; + return; + } + + if (req->compression_mode < 0 || req->compression_mode > 5) { + RCLCPP_WARN( + get_logger(), + "'compression_mode' mode not valid. Please use a value in " + "range [0,5]"); + res->message = + "'compression_mode' mode not valid. Please use a value in range " + "[0,5]"; + res->success = false; + return; + } + switch (req->compression_mode) { + case 1: + _svoRecCompression = sl::SVO_COMPRESSION_MODE::H264; + break; + case 3: + _svoRecCompression = sl::SVO_COMPRESSION_MODE::H264_LOSSLESS; + break; + case 4: + _svoRecCompression = sl::SVO_COMPRESSION_MODE::H265_LOSSLESS; + break; + case 5: + _svoRecCompression = sl::SVO_COMPRESSION_MODE::LOSSLESS; + break; + default: + _svoRecCompression = sl::SVO_COMPRESSION_MODE::H265; + break; + } + _svoRecFramerate = req->target_framerate; + _svoRecTranscode = req->input_transcode; + _svoRecFilename = req->svo_filename; + + if (_svoRecFilename.empty()) { + _svoRecFilename = "zed_one.svo2"; + } + + std::string err; + + if (!startSvoRecording(err)) { + res->message = "Error starting SVO recording: " + err; + res->success = false; + return; + } + + RCLCPP_INFO(get_logger(), "SVO Recording started: "); + RCLCPP_INFO_STREAM(get_logger(), " * Bitrate: " << _svoRecBitrate); + RCLCPP_INFO_STREAM( + get_logger(), + " * Compression mode: " << sl::toString(_svoRecCompression).c_str()); + RCLCPP_INFO_STREAM(get_logger(), " * Framerate: " << _svoRecFramerate); + RCLCPP_INFO_STREAM( + get_logger(), + " * Input Transcode: " << (_svoRecTranscode ? "TRUE" : "FALSE")); + RCLCPP_INFO_STREAM( + get_logger(), " * Filename: " << (_svoRecFilename.empty() ? + "zed_one.svo2" : + _svoRecFilename)); + + res->message = "SVO Recording started"; + res->success = true; +} + +void ZedCameraOne::callback_stopSvoRec( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + (void)req; + + RCLCPP_INFO(get_logger(), "** Stop SVO Recording service called **"); + + std::lock_guard lock(_recMutex); + + if (!_recording) { + RCLCPP_WARN(get_logger(), "SVO Recording is NOT enabled"); + res->message = "SVO Recording is NOT enabled"; + res->success = false; + return; + } + + stopSvoRecording(); + + RCLCPP_INFO(get_logger(), "SVO Recording stopped"); + res->message = "SVO Recording stopped"; + res->success = true; +} + +void ZedCameraOne::callback_pauseSvoInput( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Pause SVO Input service called **"); + + std::lock_guard lock(_recMutex); + + if (!_svoMode) { + RCLCPP_WARN(get_logger(), "The node is not using an SVO as input"); + res->message = "The node is not using an SVO as inpu"; + res->success = false; + return; + } + + if (_svoRealtime) { + RCLCPP_WARN( + get_logger(), + "SVO input can be paused only if SVO is not in RealTime mode"); + res->message = + "SVO input can be paused only if SVO is not in RealTime mode"; + res->success = false; + _svoPause = false; + return; + } + + if (!_svoPause) { + RCLCPP_WARN(get_logger(), "SVO is paused"); + res->message = "SVO is paused"; + _svoPause = true; + } else { + RCLCPP_WARN(get_logger(), "SVO is playing"); + res->message = "SVO is playing"; + _svoPause = false; + } + res->success = true; +} + +void ZedCameraOne::callback_setSvoFrame( + const std::shared_ptr request_header, + const std::shared_ptr req, + std::shared_ptr res) +{ + (void)request_header; + + RCLCPP_INFO(get_logger(), "** Set SVO Frame service called **"); + + constexpr double SVO_FRAME_SET_MIN_INTERVAL = + 0.5; // Minimum interval in seconds between frame changes to prevent + // excessive seeking + + // ----> Check service call frequency + if (_setSvoFrameCheckTimer.toc() < SVO_FRAME_SET_MIN_INTERVAL) { + RCLCPP_WARN(get_logger(), "SVO frame set too fast"); + res->message = "SVO frame set too fast"; + res->success = false; + return; + } + _setSvoFrameCheckTimer.tic(); + // <---- Check service call frequency + + std::lock_guard lock(_recMutex); + + if (!_svoMode) { + RCLCPP_WARN(get_logger(), "The node is not using an SVO as input"); + res->message = "The node is not using an SVO as input"; + res->success = false; + return; + } + + int frame = req->frame_id; + int svo_frames = _zed->getSVONumberOfFrames(); + if (frame >= svo_frames) { + std::stringstream ss; + ss << "Frame number is out of range. SVO has " << svo_frames << " frames"; + RCLCPP_WARN(get_logger(), ss.str().c_str()); + res->message = ss.str(); + res->success = false; + return; + } + + _zed->setSVOPosition(frame); + RCLCPP_INFO_STREAM(get_logger(), "SVO frame set to " << frame); + res->message = "SVO frame set to " + std::to_string(frame); + + // if svo is paused, ensure one grab can update topics + if (_svoPause) { + _grabOnce = true; + _grabImuOnce = true; + } + + res->success = true; +} + +bool ZedCameraOne::startSvoRecording(std::string & errMsg) +{ + sl::RecordingParameters params; + + params.bitrate = _svoRecBitrate; + params.compression_mode = _svoRecCompression; + params.target_framerate = _svoRecFramerate; + params.transcode_streaming_input = _svoRecTranscode; + params.video_filename = _svoRecFilename.c_str(); + + sl::ERROR_CODE err = _zed->enableRecording(params); + errMsg = sl::toString(err); + + if (err != sl::ERROR_CODE::SUCCESS) { + RCLCPP_ERROR_STREAM( + get_logger(), + "Error starting SVO recording: " << errMsg); + return false; + } + + _recording = true; + + return true; +} + +void ZedCameraOne::stopSvoRecording() +{ + if (_recording) { + _recording = false; + _zed->disableRecording(); + } +} + +void ZedCameraOne::startHeartbeatTimer() +{ + if (_heartbeatTimer != nullptr) { + _heartbeatTimer->cancel(); + } + + std::chrono::milliseconds pubPeriod_msec(HEARTBEAT_INTERVAL_MS); + _heartbeatTimer = create_wall_timer( + std::chrono::duration_cast(pubPeriod_msec), + std::bind(&ZedCameraOne::callback_pubHeartbeat, this)); +} + +} // namespace stereolabs + +#include "rclcpp_components/register_node_macro.hpp" + +// Register the component with class_loader. +// This acts as a sort of entry point, allowing the component to be discoverable +// when its library is being loaded into a running process. +RCLCPP_COMPONENTS_REGISTER_NODE(stereolabs::ZedCameraOne) diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_sensors.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_sensors.cpp new file mode 100644 index 0000000000..35f5cf909c --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_sensors.cpp @@ -0,0 +1,631 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zed_camera_one_component.hpp" +#include "sl_logging.hpp" + +using namespace std::chrono_literals; + +namespace stereolabs +{ + +void ZedCameraOne::getSensorsParams() +{ + rclcpp::Parameter paramVal; + + rcl_interfaces::msg::ParameterDescriptor read_only_descriptor; + read_only_descriptor.read_only = true; + + RCLCPP_INFO(get_logger(), "=== SENSORS parameters ==="); + + sl_tools::getParam( + shared_from_this(), "sensors.publish_imu_tf", + _publishSensImuTF, _publishSensImuTF, " * Publish IMU TF: "); + sl_tools::getParam( + shared_from_this(), "sensors.sensors_pub_rate", + _sensPubRate, _sensPubRate, + " * Sensors publishing rate [Hz]: ", true, 1.0, 400.0); +} + +void ZedCameraOne::initSensorPublishers() +{ + RCLCPP_INFO(get_logger(), " +++ SENSORS TOPICS +++"); + + // ----> Advertised topics + const std::string imu_topic_root = "imu/"; + const std::string imu_topic = imu_topic_root + "data"; + const std::string imu_raw_topic = imu_topic_root + "data_raw"; + const std::string temp_topic = "temperature"; + + // Helper to build topic names + auto make_topic = + [&](const std::string & type) { + std::string topic = _topicRoot + type; + return get_node_topics_interface()->resolve_topic_name(topic); + }; + + _sensImuTopic = make_topic(imu_topic); + _sensImuRawTopic = make_topic(imu_raw_topic); + _sensTempTopic = make_topic(temp_topic); + // <---- Advertised topics + + // ----> Create publishers + + // Sensors publishers + if (_publishSensImu) { + _pubImu = this->create_publisher(_sensImuTopic, _qos, _pubOpt); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << _pubImu->get_topic_name()); + } + + if (_publishSensImuRaw) { + _pubImuRaw = this->create_publisher(_sensImuRawTopic, _qos, _pubOpt); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << _pubImuRaw->get_topic_name()); + } + + if (_publishSensTemp) { + _pubTemp = this->create_publisher(_sensTempTopic, _qos, _pubOpt); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << _pubTemp->get_topic_name()); + } + // <---- Create publishers +} + +void ZedCameraOne::threadFunc_pubSensorsData() +{ + DEBUG_STREAM_SENS("Sensors thread started"); + + // Set the name of the pubSensorsData thread for easier identification in + // system monitors + pthread_setname_np(pthread_self(), (get_name() + std::string("_pubSensorsData")).c_str()); + setupSensorThreadScheduling(); + + DEBUG_STREAM_SENS("Sensors thread loop starting..."); + _lastTs_imu = TIMEZERO_ROS; + + constexpr auto SVO_PAUSE_POLL_INTERVAL = + 100ms; // Poll interval when SVO is paused + + while (true) { + if (handleSensorThreadInterruption()) {break;} + + if (_svoMode && _svoPause) { + if (!_grabImuOnce) { + rclcpp::sleep_for(SVO_PAUSE_POLL_INTERVAL); + continue; + } else { + _grabImuOnce = false; // Reset the flag and grab the IMU data + } + } + + if (!waitForCameraOpen()) {continue;} + if (!waitForSensorSubscribers()) {continue;} + if (!handleSensorPublishing()) {continue;} + adjustSensorPublishingFrequency(); + } + + DEBUG_STREAM_SENS("Sensors thread finished"); +} + +// Helper: Setup thread scheduling for sensors thread +void ZedCameraOne::setupSensorThreadScheduling() +{ + if (_changeThreadSched) { + DEBUG_STREAM_ADV("Sensors thread settings"); + if (_debugAdvanced) { + int policy; + sched_param par; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * Default Sensors thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + + sched_param par; + par.sched_priority = + (_threadSchedPolicy == "SCHED_FIFO" || _threadSchedPolicy == "SCHED_RR") ? + _threadPrioSens : + 0; + int sched_policy = SCHED_OTHER; + if (_threadSchedPolicy == "SCHED_BATCH") { + sched_policy = SCHED_BATCH; + } else if (_threadSchedPolicy == "SCHED_FIFO") { + sched_policy = SCHED_FIFO; + } else if (_threadSchedPolicy == "SCHED_RR") { + sched_policy = SCHED_RR; + } + + if (pthread_setschedparam(pthread_self(), sched_policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to set thread params! - " + << std::strerror(errno)); + } + + if (_debugAdvanced) { + int policy; + if (pthread_getschedparam(pthread_self(), &policy, &par)) { + RCLCPP_WARN_STREAM( + get_logger(), " ! Failed to get thread policy! - " + << std::strerror(errno)); + } else { + DEBUG_STREAM_ADV( + " * New Sensors thread (#" + << pthread_self() << ") settings - Policy: " + << sl_tools::threadSched2Str(policy).c_str() + << " - Priority: " << par.sched_priority); + } + } + } +} + +// Helper: Handle thread interruption and shutdown +bool ZedCameraOne::handleSensorThreadInterruption() +{ + try { + if (!rclcpp::ok()) { + DEBUG_STREAM_SENS("Ctrl+C received: stopping sensors thread"); + _threadStop = true; + return true; + } + if (_threadStop) { + DEBUG_STREAM_SENS("[threadFunc_pubSensorsData] (2): Sensors thread stopped"); + return true; + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_COMM("[threadFunc_pubSensorsData] Generic exception."); + return false; + } + return false; +} + +// Helper: Wait for camera to be open +bool ZedCameraOne::waitForCameraOpen() +{ + if (!_zed->isOpened()) { + DEBUG_STREAM_SENS("[threadFunc_pubSensorsData] the camera is not open"); + rclcpp::sleep_for(200ms); + return false; + } + return true; +} + +// Helper: Wait for sensor topic subscribers +bool ZedCameraOne::waitForSensorSubscribers() +{ + _imuPublishing = areSensorsTopicsSubscribed(); + if (!_imuPublishing && !_publishSensImuTF) { + rclcpp::sleep_for(200ms); + return false; + } + return true; +} + +// Helper: Handle sensor publishing and sleep if needed +bool ZedCameraOne::handleSensorPublishing() +{ + if (!publishSensorsData()) { + auto sleep_msec = static_cast(_sensRateComp * (1000. / _sensPubRate)); + sleep_msec = std::max(1, sleep_msec); + DEBUG_STREAM_SENS("[threadFunc_pubSensorsData] Thread sleep: " << sleep_msec << " msec"); + rclcpp::sleep_for(std::chrono::milliseconds(sleep_msec)); + return false; + } + return true; +} + +// Helper: Adjust publishing frequency compensation +void ZedCameraOne::adjustSensorPublishingFrequency() +{ + double avg_freq = 1. / _imuPeriodMean_sec->getAvg(); + double err = std::fabs(_sensPubRate - avg_freq); + const double COMP_P_GAIN = 0.0005; + + if (avg_freq < _sensPubRate) { + _sensRateComp -= COMP_P_GAIN * err; + } else if (avg_freq > _sensPubRate) { + _sensRateComp += COMP_P_GAIN * err; + } + + _sensRateComp = std::max(0.05, _sensRateComp); + _sensRateComp = std::min(2.0, _sensRateComp); + DEBUG_STREAM_SENS("[threadFunc_pubSensorsData] _sensRateComp: " << _sensRateComp); +} + +void ZedCameraOne::startTempPubTimer() +{ + if (_tempPubTimer != nullptr) { + _tempPubTimer->cancel(); + } + + std::chrono::milliseconds pubPeriod_msec(TEMP_PUB_INTERVAL_MS); + _tempPubTimer = create_wall_timer( + std::chrono::duration_cast(pubPeriod_msec), + std::bind(&ZedCameraOne::callback_pubTemp, this)); +} + +void ZedCameraOne::callback_pubTemp() +{ + DEBUG_STREAM_ONCE_SENS("Temperatures callback called"); + + if (_grabStatus != sl::ERROR_CODE::SUCCESS) { + DEBUG_SENS("Camera not ready"); + return; + } + + // ----> Always update temperature values for diagnostic + sl::SensorsData sens_data; + sl::ERROR_CODE err = _zed->getSensorsData(sens_data, sl::TIME_REFERENCE::CURRENT); + if (err != sl::ERROR_CODE::SUCCESS) { + // Only warn if not in SVO mode or if the error is not a benign sensor + // unavailability + if (!_svoMode || err != sl::ERROR_CODE::SENSORS_NOT_AVAILABLE) { + RCLCPP_WARN_STREAM( + get_logger(), + "[callback_pubTemp] sl::getSensorsData error: " + << sl::toString(err).c_str()); + } + return; + } + + sens_data.temperature.get( + sl::SensorsData::TemperatureData::SENSOR_LOCATION::IMU, _tempImu); + DEBUG_STREAM_SENS("Camera temperature: " << _tempImu << "°C"); + // <---- Always update temperature values for diagnostic + + // ----> Subscribers count + size_t tempSubCount = 0; + + try { + if (_pubTemp) { + tempSubCount = count_subscribers(_pubTemp->get_topic_name()); + DEBUG_STREAM_SENS("Temperature subscribers: " << static_cast(tempSubCount)); + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_SENS( + "callback_pubTemp: Exception while counting subscribers"); + return; + } + // <---- Subscribers count + + // ----> Publish temperature + if (tempSubCount > 0) { + auto imuTempMsg = std::make_unique(); + + imuTempMsg->header.stamp = get_clock()->now(); + + imuTempMsg->header.frame_id = _imuFrameId; + imuTempMsg->temperature = static_cast(_tempImu); + imuTempMsg->variance = 0.0; + + DEBUG_SENS("Publishing IMU TEMP message"); + try { + if (_pubTemp) { + _pubTemp->publish(std::move(imuTempMsg)); + } + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } + } + // <---- Publish temperature +} + +bool ZedCameraOne::publishSensorsData() +{ + if (_grabStatus != sl::ERROR_CODE::SUCCESS) { + DEBUG_SENS("Camera not ready"); + return false; + } + + sl::SensorsData sens_data; + sl::ERROR_CODE err = _zed->getSensorsData(sens_data, sl::TIME_REFERENCE::CURRENT); + if (err != sl::ERROR_CODE::SUCCESS) { + // Only warn if not in SVO mode or if the error is not a benign sensor unavailability + if (!_svoMode || err != sl::ERROR_CODE::SENSORS_NOT_AVAILABLE) { + RCLCPP_WARN_STREAM( + get_logger(), + "[publishSensorsData] sl::getSensorsData error: " << sl::toString(err).c_str()); + } + return false; + } + + rclcpp::Time ts_imu = sl_tools::slTime2Ros(sens_data.imu.timestamp); + double dT = ts_imu.seconds() - _lastTs_imu.seconds(); + _lastTs_imu = ts_imu; + bool new_imu_data = (dT > 0.0); + + if (!new_imu_data) { + DEBUG_STREAM_SENS("[publishSensorsData] No new sensors data"); + return false; + } + + updateImuFreqDiagnostics(dT); + + publishImuFrameAndTopic(); + + if (_imuSubCount > 0) { + publishImuMsg(ts_imu, sens_data); + } + + if (_imuRawSubCount > 0) { + publishImuRawMsg(ts_imu, sens_data); + } + + return true; +} + +void ZedCameraOne::updateImuFreqDiagnostics(double dT) +{ + DEBUG_STREAM_SENS("SENSOR LAST PERIOD: " << dT << " sec @" << 1. / dT << " Hz"); + auto elapsed = _imuFreqTimer.toc(); + _imuFreqTimer.tic(); + double mean = _imuPeriodMean_sec->addValue(elapsed); + _pubImu_sec->addValue(mean); + DEBUG_STREAM_SENS("IMU MEAN freq: " << 1. / mean); +} + +void ZedCameraOne::publishImuMsg(const rclcpp::Time & ts_imu, const sl::SensorsData & sens_data) +{ + if (!_pubImu) { + DEBUG_STREAM_SENS("[publishImuMsg] _pubImu is null"); + return; + } + + DEBUG_STREAM_SENS( + "[publishImuMsg] IMU subscribers: " << static_cast(_imuSubCount)); + auto imuMsg = std::make_unique(); + imuMsg->header.stamp = ts_imu; + imuMsg->header.frame_id = _imuFrameId; + + imuMsg->orientation.x = sens_data.imu.pose.getOrientation()[0]; + imuMsg->orientation.y = sens_data.imu.pose.getOrientation()[1]; + imuMsg->orientation.z = sens_data.imu.pose.getOrientation()[2]; + imuMsg->orientation.w = sens_data.imu.pose.getOrientation()[3]; + + imuMsg->angular_velocity.x = sens_data.imu.angular_velocity[0] * DEG2RAD; + imuMsg->angular_velocity.y = sens_data.imu.angular_velocity[1] * DEG2RAD; + imuMsg->angular_velocity.z = sens_data.imu.angular_velocity[2] * DEG2RAD; + + imuMsg->linear_acceleration.x = sens_data.imu.linear_acceleration[0]; + imuMsg->linear_acceleration.y = sens_data.imu.linear_acceleration[1]; + imuMsg->linear_acceleration.z = sens_data.imu.linear_acceleration[2]; + + for (int i = 0; i < 3; ++i) { + int r = i; + imuMsg->orientation_covariance[i * 3 + 0] = sens_data.imu.pose_covariance.r[r * 3 + 0] * + DEG2RAD * DEG2RAD; + imuMsg->orientation_covariance[i * 3 + 1] = sens_data.imu.pose_covariance.r[r * 3 + 1] * + DEG2RAD * DEG2RAD; + imuMsg->orientation_covariance[i * 3 + 2] = sens_data.imu.pose_covariance.r[r * 3 + 2] * + DEG2RAD * DEG2RAD; + + imuMsg->linear_acceleration_covariance[i * 3 + + 0] = sens_data.imu.linear_acceleration_covariance.r[r * 3 + 0]; + imuMsg->linear_acceleration_covariance[i * 3 + + 1] = sens_data.imu.linear_acceleration_covariance.r[r * 3 + 1]; + imuMsg->linear_acceleration_covariance[i * 3 + + 2] = sens_data.imu.linear_acceleration_covariance.r[r * 3 + 2]; + + imuMsg->angular_velocity_covariance[i * 3 + + 0] = sens_data.imu.angular_velocity_covariance.r[r * 3 + 0] * DEG2RAD * DEG2RAD; + imuMsg->angular_velocity_covariance[i * 3 + + 1] = sens_data.imu.angular_velocity_covariance.r[r * 3 + 1] * DEG2RAD * DEG2RAD; + imuMsg->angular_velocity_covariance[i * 3 + + 2] = sens_data.imu.angular_velocity_covariance.r[r * 3 + 2] * DEG2RAD * DEG2RAD; + } + + try { + _pubImu->publish(std::move(imuMsg)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } +} + +void ZedCameraOne::publishImuRawMsg(const rclcpp::Time & ts_imu, const sl::SensorsData & sens_data) +{ + if (!_pubImuRaw) { + DEBUG_STREAM_SENS("[publishImuRawMsg] _pubImuRaw is null"); + return; + } + + DEBUG_STREAM_SENS( + "[publishImuRawMsg] IMU RAW subscribers: " + << static_cast(_imuRawSubCount)); + auto imuRawMsg = std::make_unique(); + imuRawMsg->header.stamp = ts_imu; + imuRawMsg->header.frame_id = _imuFrameId; + + imuRawMsg->angular_velocity.x = sens_data.imu.angular_velocity_uncalibrated[0] * DEG2RAD; + imuRawMsg->angular_velocity.y = sens_data.imu.angular_velocity_uncalibrated[1] * DEG2RAD; + imuRawMsg->angular_velocity.z = sens_data.imu.angular_velocity_uncalibrated[2] * DEG2RAD; + + imuRawMsg->linear_acceleration.x = sens_data.imu.linear_acceleration_uncalibrated[0]; + imuRawMsg->linear_acceleration.y = sens_data.imu.linear_acceleration_uncalibrated[1]; + imuRawMsg->linear_acceleration.z = sens_data.imu.linear_acceleration_uncalibrated[2]; + + for (int i = 0; i < 3; ++i) { + int r = i; + imuRawMsg->linear_acceleration_covariance[i * 3 + + 0] = sens_data.imu.linear_acceleration_covariance.r[r * 3 + 0]; + imuRawMsg->linear_acceleration_covariance[i * 3 + + 1] = sens_data.imu.linear_acceleration_covariance.r[r * 3 + 1]; + imuRawMsg->linear_acceleration_covariance[i * 3 + + 2] = sens_data.imu.linear_acceleration_covariance.r[r * 3 + 2]; + + imuRawMsg->angular_velocity_covariance[i * 3 + + 0] = sens_data.imu.angular_velocity_covariance.r[r * 3 + 0] * DEG2RAD * DEG2RAD; + imuRawMsg->angular_velocity_covariance[i * 3 + + 1] = sens_data.imu.angular_velocity_covariance.r[r * 3 + 1] * DEG2RAD * DEG2RAD; + imuRawMsg->angular_velocity_covariance[i * 3 + + 2] = sens_data.imu.angular_velocity_covariance.r[r * 3 + 2] * DEG2RAD * DEG2RAD; + } + + try { + _pubImuRaw->publish(std::move(imuRawMsg)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } +} + +void ZedCameraOne::publishImuFrameAndTopic() +{ + if (!_publishSensImuTF && !_publishSensImuTransf) { + return; + } + + if (!_usingIPC && _staticImuTfPublished) { + DEBUG_ONCE_TF( + "Static Imu TF and Transient Local message already published"); + return; + } + + sl::Orientation sl_rot = _slCamImuTransf.getOrientation(); + sl::Translation sl_tr = _slCamImuTransf.getTranslation(); + + auto cameraImuTransfMsg = std::make_unique(); + + cameraImuTransfMsg->header.stamp = get_clock()->now(); + cameraImuTransfMsg->header.frame_id = _camImgFrameId; + cameraImuTransfMsg->child_frame_id = _imuFrameId; + + cameraImuTransfMsg->transform.rotation.x = sl_rot.ox; + cameraImuTransfMsg->transform.rotation.y = sl_rot.oy; + cameraImuTransfMsg->transform.rotation.z = sl_rot.oz; + cameraImuTransfMsg->transform.rotation.w = sl_rot.ow; + + cameraImuTransfMsg->transform.translation.x = sl_tr.x; + cameraImuTransfMsg->transform.translation.y = sl_tr.y; + cameraImuTransfMsg->transform.translation.z = sl_tr.z; + + // ----> Publish CAM/IMU Transform + if (_publishSensImuTransf) { + try { + size_t sub_count = 0; + if (_pubCamImuTransf) { + sub_count = count_subscribers(_pubCamImuTransf->get_topic_name()); + DEBUG_STREAM_SENS("Camera-IMU Transform subscribers: " << static_cast(sub_count)); + } + + if (sub_count && _pubCamImuTransf) { + _pubCamImuTransf->publish(std::move(cameraImuTransfMsg)); + } + } catch (const std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception."); + } + } + // <---- Publish CAM/IMU Transform + + // ----> Broadcast CAM/IMU TF + if (!_publishSensImuTF) { + return; + } + + auto transformStamped = std::make_unique(); + + transformStamped->header.stamp = get_clock()->now(); + transformStamped->header.frame_id = _camImgFrameId; + transformStamped->child_frame_id = _imuFrameId; + + transformStamped->transform.rotation.x = sl_rot.ox; + transformStamped->transform.rotation.y = sl_rot.oy; + transformStamped->transform.rotation.z = sl_rot.oz; + transformStamped->transform.rotation.w = sl_rot.ow; + + transformStamped->transform.translation.x = sl_tr.x; + transformStamped->transform.translation.y = sl_tr.y; + transformStamped->transform.translation.z = sl_tr.z; + + if (_usingIPC) { + _tfBroadcaster->sendTransform(*transformStamped); + DEBUG_STREAM_TF( + "Broadcasted new dynamic transform: " + << transformStamped->header.frame_id << " -> " << transformStamped->child_frame_id); + } else { + _staticTfBroadcaster->sendTransform(*transformStamped); + DEBUG_STREAM_TF( + "Broadcasted new static transform: " + << transformStamped->header.frame_id << " -> " << transformStamped->child_frame_id); + } + + double elapsed_sec = _imuTfFreqTimer.toc(); + _pubImuTF_sec->addValue(elapsed_sec); + _imuTfFreqTimer.tic(); + // <---- Broadcast CAM/IMU TF + + // Debug info + if (_debugTf) { + double roll, pitch, yaw; + tf2::Matrix3x3( + tf2::Quaternion( + transformStamped->transform.rotation.x, + transformStamped->transform.rotation.y, + transformStamped->transform.rotation.z, + transformStamped->transform.rotation.w)) + .getRPY(roll, pitch, yaw); + DEBUG_STREAM_TF( + "TF [" << transformStamped->header.frame_id << " -> " + << transformStamped->child_frame_id << "] Position: (" + << transformStamped->transform.translation.x << ", " + << transformStamped->transform.translation.y << ", " + << transformStamped->transform.translation.z + << ") - Orientation RPY: (" << roll * RAD2DEG << ", " + << pitch * RAD2DEG << ", " << yaw * RAD2DEG << ")"); + } + + _staticImuTfPublished = true; +} + +bool ZedCameraOne::areSensorsTopicsSubscribed() +{ + try { + if (_pubImu) { + _imuSubCount = _pubImu->get_subscription_count(); + } else { + _imuSubCount = 0; + } + if (_pubImuRaw) { + _imuRawSubCount = _pubImuRaw->get_subscription_count(); + } else { + _imuRawSubCount = 0; + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_SENS( + "areSensorsTopicsSubscribed: Exception while counting subscribers"); + return false; + } + + DEBUG_STREAM_SENS( + "[areSensorsTopicsSubscribed] IMU subscribers: " << _imuSubCount); + DEBUG_STREAM_SENS( + "[areSensorsTopicsSubscribed] IMU RAW subscribers: " << _imuRawSubCount); + + return (_imuSubCount + _imuRawSubCount) > 0; +} + +} // namespace stereolabs diff --git a/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_video.cpp b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_video.cpp new file mode 100644 index 0000000000..5a90ff5a0e --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_components/src/zed_camera_one/src/zed_camera_one_component_video.cpp @@ -0,0 +1,1121 @@ +// Copyright 2025 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "zed_camera_one_component.hpp" +#include "sl_logging.hpp" + +#include + +#include +#include + +namespace stereolabs +{ + +void ZedCameraOne::getVideoParams() +{ + rclcpp::Parameter paramVal; + + RCLCPP_INFO(get_logger(), "=== CAMERA CONTROL parameters ==="); + + sl_tools::getParam( + shared_from_this(), "video.enable_hdr", _enableHDR, + _enableHDR, " * Enable HDR: "); + + sl_tools::getParam( + shared_from_this(), "video.saturation", _camSaturation, + _camSaturation, " * Saturation: ", true, 0, 8); + _camDynParMapChanged["video.saturation"] = true; + sl_tools::getParam( + shared_from_this(), "video.sharpness", _camSharpness, + _camSharpness, " * Sharpness: ", true, 0, 8); + _camDynParMapChanged["video.sharpness"] = true; + sl_tools::getParam( + shared_from_this(), "video.gamma", _camGamma, _camGamma, + " * Gamma: ", true, 1, 9); + _camDynParMapChanged["video.gamma"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_whitebalance", _camAutoWB, + _camAutoWB, " * Auto White Balance: ", true); + _camDynParMapChanged["video.auto_whitebalance"] = true; + sl_tools::getParam( + shared_from_this(), "video.whitebalance_temperature", + _camWBTemp, _camWBTemp, + " * White Balance Temp (x100): ", true, 28, 65); + _camDynParMapChanged["video.whitebalance_temperature"] = true; + + sl_tools::getParam( + shared_from_this(), "video.auto_exposure", + _camAutoExposure, _camAutoExposure, + " * Auto Exposure: ", true); + _camDynParMapChanged["video.auto_exposure"] = true; + sl_tools::getParam( + shared_from_this(), "video.exposure_time", _camExpTime, + _camExpTime, " * Exposure (us): ", true, 28, 30000); + _camDynParMapChanged["video.exposure_time"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_exposure_time_range_min", + _camAutoExpTimeRangeMin, _camAutoExpTimeRangeMin, + " * Auto Exp Time Min (us): ", true, 28, 30000); + _camDynParMapChanged["video.auto_exposure_time_range_min"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_exposure_time_range_max", + _camAutoExpTimeRangeMax, _camAutoExpTimeRangeMax, + " * Auto Exp Time Max (us): ", true, 28, 30000); + _camDynParMapChanged["video.auto_exposure_time_range_max"] = true; + sl_tools::getParam( + shared_from_this(), "video.exposure_compensation", + _camExposureComp, _camExposureComp, + " * Exposure Compensation: ", true, 0, 100); + _camDynParMapChanged["video.exposure_compensation"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_analog_gain", + _camAutoAnalogGain, _camAutoAnalogGain, + " * Auto Analog Gain: ", true); + _camDynParMapChanged["video.auto_analog_gain"] = true; + sl_tools::getParam( + shared_from_this(), "video.analog_gain", _camAnalogGain, + _camAnalogGain, " * Analog Gain: ", true, 1000, 16000); + _camDynParMapChanged["video.analog_gain"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_analog_gain_range_min", + _camAutoAnalogGainRangeMin, _camAutoAnalogGainRangeMin, + " * Analog Gain Min: ", true, 1000, 16000); + _camDynParMapChanged["video.auto_analog_gain_range_min"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_analog_gain_range_max", + _camAutoAnalogGainRangeMax, _camAutoAnalogGainRangeMax, + " * Analog Gain Max: ", true, 1000, 16000); + _camDynParMapChanged["video.auto_analog_gain_range_max"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_digital_gain", + _camAutoDigitalGain, _camAutoDigitalGain, + " * Auto Digital Gain: ", true); + _camDynParMapChanged["video.auto_digital_gain"] = true; + sl_tools::getParam( + shared_from_this(), "video.digital_gain", _camDigitalGain, + _camDigitalGain, " * Digital Gain: ", true, 1, 256); + _camDynParMapChanged["video.digital_gain"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_digital_gain_range_min", + _camAutoDigitalGainRangeMin, _camAutoDigitalGainRangeMin, + " * Digital Gain Min: ", true, 1, 256); + _camDynParMapChanged["video.auto_digital_gain_range_min"] = true; + sl_tools::getParam( + shared_from_this(), "video.auto_digital_gain_range_max", + _camAutoDigitalGainRangeMax, _camAutoDigitalGainRangeMax, + " * Digital Gain Max: ", true, 1, 256); + _camDynParMapChanged["video.auto_digital_gain_range_max"] = true; + sl_tools::getParam( + shared_from_this(), "video.denoising", _camDenoising, + _camDenoising, " * Denoising: ", true, 0, 100); + _camDynParMapChanged["video.denoising"] = true; + + _triggerUpdateDynParams = true; +} + +void ZedCameraOne::initVideoPublishers() +{ + RCLCPP_INFO(get_logger(), " +++ IMAGE TOPICS +++"); + + // ----> Advertised topics + const std::string sensor = "rgb/"; + const std::string rect_prefix = "rect/"; + const std::string raw_prefix = "raw/"; + const std::string color_prefix = "color/"; + const std::string gray_prefix = "gray/"; + const std::string image_topic = "image"; + + // Helper to build topic names + auto make_topic = + [&](const std::string & sensor, const std::string & color_mode, const std::string & rect_raw, + const std::string & type) { + std::string topic = _topicRoot + sensor + color_mode + rect_raw + type; + return get_node_topics_interface()->resolve_topic_name(topic); + }; + + _imgColorTopic = make_topic(sensor, color_prefix, rect_prefix, image_topic); + _imgColorRawTopic = make_topic(sensor, color_prefix, raw_prefix, image_topic); + _imgGrayTopic = make_topic(sensor, gray_prefix, rect_prefix, image_topic); + _imgRawGrayTopic = make_topic(sensor, gray_prefix, raw_prefix, image_topic); + // <---- Advertised topics + + // ----> Create publishers + auto qos = _qos.get_rmw_qos_profile(); + + // Publishers logging + auto log_cam_pub = [&](const auto & pub) { + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << pub.getTopic()); + auto transports = image_transport::getLoadableTransports(); + for (const auto & transport : transports) { + std::string transport_copy = transport; + auto pos = transport_copy.find('/'); + if (pos != std::string::npos) { + transport_copy.erase(0, pos); + } + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " + << pub.getTopic() << transport_copy + << " [image_transport]"); + } + }; + + // Camera publishers + if (_nitrosDisabled) { + if (_publishImgRgb) { + _pubColorImg = image_transport::create_publisher(this, _imgColorTopic, qos); + log_cam_pub(_pubColorImg); + + if (_publishImgRaw) { + _pubColorRawImg = image_transport::create_publisher(this, _imgColorRawTopic, qos); + log_cam_pub(_pubColorRawImg); + } + } + + if (_publishImgGray) { + _pubGrayImg = image_transport::create_publisher(this, _imgGrayTopic, qos); + log_cam_pub(_pubGrayImg); + + if (_publishImgRaw) { + _pubGrayRawImg = image_transport::create_publisher(this, _imgRawGrayTopic, qos); + log_cam_pub(_pubGrayRawImg); + } + } + + + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + // Nitros publishers lambda + auto make_nitros_img_pub = [&](const std::string & topic) { + auto ret = std::make_shared>( + this, topic, nvidia::isaac_ros::nitros::nitros_image_bgra8_t::supported_type_name, + nvidia::isaac_ros::nitros::NitrosDiagnosticsConfig(), _qos); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << topic); + RCLCPP_INFO_STREAM( + get_logger(), " * Advertised on topic: " << topic + "/nitros [isaac_ros_nitros]"); + return ret; + }; + if (_publishImgRgb) { + _nitrosPubColorImg = make_nitros_img_pub(_imgColorTopic); + + if (_publishImgRaw) { + _nitrosPubColorRawImg = make_nitros_img_pub(_imgColorRawTopic); + } + } + + if (_publishImgGray) { + _nitrosPubGrayImg = make_nitros_img_pub(_imgGrayTopic); + if (_publishImgRaw) { + _nitrosPubGrayRawImg = make_nitros_img_pub(_imgRawGrayTopic); + } + } +#endif + } + // <---- Create publishers + + // ----> Camera Info publishers + // Lambda to create and log CameraInfo publishers + auto make_cam_info_pub = [&](const std::string & topic) { + std::string info_topic = image_transport::getCameraInfoTopic(topic); + auto pub = create_publisher(info_topic, _qos); + RCLCPP_INFO_STREAM(get_logger(), " * Advertised on topic: " << pub->get_topic_name()); + return pub; + }; + + // Lambda to create and log CameraInfo publishers for image_transport or nitros + auto make_cam_info_trans_pub = [&](const std::string & topic) { + std::string info_topic = topic + "/camera_info"; + auto pub = create_publisher(info_topic, _qos); + RCLCPP_INFO_STREAM( + get_logger(), + " * Advertised on topic: " << pub->get_topic_name()); + return pub; + }; + + if (_publishImgRgb) { + _pubColorImgInfo = make_cam_info_pub(_imgColorTopic); + _pubColorImgInfoTrans = make_cam_info_trans_pub(_imgColorTopic); + + if (_publishImgRaw) { + _pubColorRawImgInfo = make_cam_info_pub(_imgColorRawTopic); + _pubColorRawImgInfoTrans = make_cam_info_trans_pub(_imgColorRawTopic); + } + } + + if (_publishImgGray) { + _pubGrayImgInfo = make_cam_info_pub(_imgGrayTopic); + _pubGrayImgInfoTrans = make_cam_info_trans_pub(_imgGrayTopic); + + if (_publishImgRaw) { + _pubGrayRawImgInfo = make_cam_info_pub(_imgRawGrayTopic); + _pubGrayRawImgInfoTrans = make_cam_info_trans_pub(_imgRawGrayTopic); + } + } + // <---- Camera Info publishers +} + +void ZedCameraOne::fillCamInfo( + sensor_msgs::msg::CameraInfo::SharedPtr camInfoMsg, + const std::string & frameId, bool rawParam) +{ + sl::CameraParameters zedParam; + + if (rawParam) { + zedParam = + _zed->getCameraInformation(_matResol).camera_configuration.calibration_parameters_raw; + } else { + zedParam = _zed->getCameraInformation(_matResol).camera_configuration.calibration_parameters; + } + + // https://docs.ros2.org/latest/api/sensor_msgs/msg/CameraInfo.html + + // ----> Distortion models + // ZED SDK params order: [ k1, k2, p1, p2, k3, k4, k5, k6, s1, s2, s3, s4] + // Radial (k1, k2, k3, k4, k5, k6), Tangential (p1,p2) and Prism (s1, s2, s3, + // s4) distortion. Prism not currently used. + + // ROS2 order (OpenCV) -> k1,k2,p1,p2,k3,k4,k5,k6,s1,s2,s3,s4 + // All ZED X One models use RATIONAL_POLYNOMIAL + camInfoMsg->distortion_model = + sensor_msgs::distortion_models::RATIONAL_POLYNOMIAL; + + camInfoMsg->d.resize(8); + for (size_t i = 0; i < 8; i++) { + camInfoMsg->d[i] = zedParam.disto[i]; + } + + // Intrinsic + camInfoMsg->k.fill(0.0); + camInfoMsg->k[0] = static_cast(zedParam.fx); + camInfoMsg->k[2] = static_cast(zedParam.cx); + camInfoMsg->k[4] = static_cast(zedParam.fy); + camInfoMsg->k[5] = static_cast(zedParam.cy); + camInfoMsg->k[8] = 1.0; + + // Rectification + camInfoMsg->r.fill(0.0); + for (size_t i = 0; i < 3; i++) { + // identity + camInfoMsg->r[i + i * 3] = 1.0; + } + + // Projection/camera matrix + camInfoMsg->p.fill(0.0); + camInfoMsg->p[0] = static_cast(zedParam.fx); + camInfoMsg->p[2] = static_cast(zedParam.cx); + camInfoMsg->p[5] = static_cast(zedParam.fy); + camInfoMsg->p[6] = static_cast(zedParam.cy); + camInfoMsg->p[10] = 1.0; + + // Image size + camInfoMsg->width = static_cast(_matResol.width); + camInfoMsg->height = static_cast(_matResol.height); + camInfoMsg->header.frame_id = frameId; +} + +void ZedCameraOne::setupCameraInfoMessages() +{ + _camInfoMsg = std::make_shared(); + _camInfoRawMsg = std::make_shared(); + + fillCamInfo(_camInfoMsg, _camOptFrameId, false); + fillCamInfo(_camInfoRawMsg, _camOptFrameId, true); +} + +bool ZedCameraOne::areImageTopicsSubscribed() +{ + _colorSubCount = 0; + _colorRawSubCount = 0; + _graySubCount = 0; + _grayRawSubCount = 0; + + try { + if (_nitrosDisabled) { + _colorSubCount = _pubColorImg.getNumSubscribers(); + _colorRawSubCount = _pubColorRawImg.getNumSubscribers(); + _graySubCount = _pubGrayImg.getNumSubscribers(); + _grayRawSubCount = _pubGrayRawImg.getNumSubscribers(); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + _colorSubCount = count_subscribers(_imgColorTopic) + count_subscribers( + _imgColorTopic + "/nitros"); + _colorRawSubCount = count_subscribers(_imgColorRawTopic) + count_subscribers( + _imgColorRawTopic + "/nitros"); + _graySubCount = count_subscribers(_imgGrayTopic) + + count_subscribers(_imgGrayTopic + "/nitros"); + _grayRawSubCount = count_subscribers(_imgRawGrayTopic) + count_subscribers( + _imgRawGrayTopic + "/nitros"); +#endif + } + } catch (...) { + rcutils_reset_error(); + DEBUG_STREAM_VD("publishImages: Exception while counting subscribers"); + return false; + } + + return (_colorSubCount + _colorRawSubCount + + _graySubCount + _grayRawSubCount + ) > 0; +} + +void ZedCameraOne::handleImageRetrievalAndPublishing() +{ + _imageSubscribed = areImageTopicsSubscribed(); + if (_imageSubscribed) { + DEBUG_STREAM_VD("Retrieving video data"); + + bool gpu = false; +#ifdef FOUND_ISAAC_ROS_NITROS + if (!_nitrosDisabled) { + gpu = true; + } +#endif + retrieveImages(gpu); + publishImages(); + _videoPublishing = true; + } else { + _videoPublishing = false; + + // Publish camera infos even if no video/depth subscribers are present + publishCameraInfos(); + } +} + +void ZedCameraOne::retrieveImages(bool gpu) +{ + bool retrieved = false; + + // ----> Retrieve all required data + DEBUG_VD("Retrieving Image Data"); + if (_colorSubCount > 0) { + retrieved |= + (sl::ERROR_CODE::SUCCESS == + _zed->retrieveImage( + _matColor, +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + _24bitMode ? sl::VIEW::LEFT_BGR : sl::VIEW::LEFT_BGRA, +#else + sl::VIEW::LEFT, +#endif + gpu ? sl::MEM::GPU : sl::MEM::CPU, _matResol)); + DEBUG_STREAM_VD( + "Color image " << _matResol.width << "x" << _matResol.height << " retrieved - timestamp: " << + _sdkGrabTS.getNanoseconds() << + " nsec"); + } + if (_colorRawSubCount > 0) { + retrieved |= (sl::ERROR_CODE::SUCCESS == + _zed->retrieveImage( + _matColorRaw, +#if (ZED_SDK_MAJOR_VERSION * 10 + ZED_SDK_MINOR_VERSION) >= 51 + _24bitMode ? sl::VIEW::LEFT_UNRECTIFIED_BGR : sl::VIEW::LEFT_UNRECTIFIED_BGRA, +#else + sl::VIEW::LEFT_UNRECTIFIED, +#endif + gpu ? sl::MEM::GPU : sl::MEM::CPU, _matResol)); + DEBUG_STREAM_VD( + "Color raw image " << _matResol.width << "x" << _matResol.height << + " retrieved - timestamp: " << _sdkGrabTS.getNanoseconds() << + " nsec"); + } + if (_graySubCount > 0) { + retrieved |= (sl::ERROR_CODE::SUCCESS == + _zed->retrieveImage( + _matGray, sl::VIEW::LEFT_GRAY, + gpu ? sl::MEM::GPU : sl::MEM::CPU, _matResol)); + DEBUG_STREAM_VD( + "Gray image " << _matResol.width << "x" << _matResol.height << " retrieved - timestamp: " << + _sdkGrabTS.getNanoseconds() << + " nsec"); + } + if (_grayRawSubCount > 0) { + retrieved |= + (sl::ERROR_CODE::SUCCESS == + _zed->retrieveImage( + _matGrayRaw, sl::VIEW::LEFT_UNRECTIFIED_GRAY, + gpu ? sl::MEM::GPU : sl::MEM::CPU, _matResol)); + DEBUG_STREAM_VD( + "Gray raw image " << _matResol.width << "x" << _matResol.height << + " retrieved - timestamp: " << _sdkGrabTS.getNanoseconds() << + " nsec"); + } + if (retrieved) { + DEBUG_VD("Image Data retrieved"); + } + // <---- Retrieve all required data +} + +void ZedCameraOne::publishImages() +{ + DEBUG_VD("=== Publish Image topics === "); + sl_tools::StopWatch vdElabTimer(get_clock()); + vdElabTimer.tic(); + + if (_sdkGrabTS.getNanoseconds() == _lastTs_grab.getNanoseconds()) { + DEBUG_VD("publishImages: ignoring not update data"); + DEBUG_STREAM_VD( + "Latest Ts: " << _lastTs_grab.getNanoseconds() + << " - New Ts: " + << _sdkGrabTS.getNanoseconds()); + return; + } + + if (_sdkGrabTS.data_ns != 0) { + double period_sec = + static_cast(_sdkGrabTS.data_ns - _lastTs_grab.data_ns) / 1e9; + DEBUG_STREAM_VD( + "IMAGE PUB LAST PERIOD: " << period_sec << " sec @" + << 1. / period_sec << " Hz"); + + _imagePeriodMean_sec->addValue(period_sec); + DEBUG_STREAM_VD( + "IMAGE PUB MEAN PERIOD: " + << _imagePeriodMean_sec->getAvg() << " sec @" + << 1. / _imagePeriodMean_sec->getAvg() << " Hz"); + } + _lastTs_grab = _sdkGrabTS; + + rclcpp::Time timeStamp; + if (_svoMode) { + timeStamp = _frameTimestamp; + } else { + timeStamp = sl_tools::slTime2Ros(_sdkGrabTS, get_clock()->get_clock_type()); + } + + publishColorImage(timeStamp); + publishColorRawImage(timeStamp); + publishGrayImage(timeStamp); + publishGrayRawImage(timeStamp); + + _imageElabMean_sec->addValue(vdElabTimer.toc()); + + double vd_period_usec = 1e6 / _camGrabFrameRate; + double elapsed_usec = _imgPubFreqTimer.toc() * 1e6; + + if (elapsed_usec < vd_period_usec) { + rclcpp::sleep_for( + std::chrono::microseconds( + static_cast(vd_period_usec - elapsed_usec))); + } + + _imgPubFreqTimer.tic(); + + DEBUG_VD("=== Video and Depth topics published === "); +} + +void ZedCameraOne::publishColorImage(const rclcpp::Time & timeStamp) +{ + if (_colorSubCount > 0) { + DEBUG_STREAM_VD("_colorSubCount: " << _colorSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + _matColor, _pubColorImg, _pubColorImgInfo, _pubColorImgInfoTrans, + _camInfoMsg, _camOptFrameId, timeStamp); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + _matColor, _nitrosPubColorImg, _pubColorImgInfo, _pubColorImgInfoTrans, + _camInfoMsg, _camOptFrameId, timeStamp); +#endif + } + } else { + publishCameraInfo(_pubColorImgInfo, _camInfoMsg, timeStamp); + publishCameraInfo(_pubColorImgInfoTrans, _camInfoMsg, timeStamp); + } +} + +void ZedCameraOne::publishColorRawImage(const rclcpp::Time & timeStamp) +{ + if (_colorRawSubCount > 0) { + DEBUG_STREAM_VD("_colorRawSubCount: " << _colorRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + _matColorRaw, _pubColorRawImg, _pubColorRawImgInfo, + _pubColorRawImgInfoTrans, _camInfoRawMsg, _camOptFrameId, timeStamp); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + _matColorRaw, _nitrosPubColorRawImg, _pubColorRawImgInfo, _pubColorRawImgInfoTrans, + _camInfoRawMsg, _camOptFrameId, timeStamp); +#endif + } + } else { + publishCameraInfo(_pubColorRawImgInfo, _camInfoRawMsg, timeStamp); + publishCameraInfo(_pubColorRawImgInfoTrans, _camInfoRawMsg, timeStamp); + } +} + +void ZedCameraOne::publishGrayImage(const rclcpp::Time & timeStamp) +{ + if (_graySubCount > 0) { + DEBUG_STREAM_VD("_graySubCount: " << _graySubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + _matGray, _pubGrayImg, _pubGrayImgInfo, _pubGrayImgInfoTrans, + _camInfoMsg, _camOptFrameId, timeStamp); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + _matGray, _nitrosPubGrayImg, _pubGrayImgInfo, _pubGrayImgInfoTrans, + _camInfoMsg, _camOptFrameId, timeStamp); +#endif + } + } else { + publishCameraInfo(_pubGrayImgInfo, _camInfoMsg, timeStamp); + publishCameraInfo(_pubGrayImgInfoTrans, _camInfoMsg, timeStamp); + } +} + +void ZedCameraOne::publishGrayRawImage(const rclcpp::Time & timeStamp) +{ + if (_grayRawSubCount > 0) { + DEBUG_STREAM_VD("_grayRawSubCount: " << _grayRawSubCount); + if (_nitrosDisabled) { + publishImageWithInfo( + _matGrayRaw, _pubGrayRawImg, _pubGrayRawImgInfo, + _pubGrayRawImgInfoTrans, _camInfoRawMsg, _camOptFrameId, timeStamp); + } else { +#ifdef FOUND_ISAAC_ROS_NITROS + publishImageWithInfo( + _matGrayRaw, _nitrosPubGrayRawImg, _pubGrayRawImgInfo, _pubGrayRawImgInfoTrans, + _camInfoRawMsg, _camOptFrameId, timeStamp); +#endif + } + } else { + publishCameraInfo(_pubGrayRawImgInfo, _camInfoRawMsg, timeStamp); + publishCameraInfo(_pubGrayRawImgInfoTrans, _camInfoRawMsg, timeStamp); + } +} + +void ZedCameraOne::publishCameraInfo( + const camInfoPub & infoPub, + camInfoMsgPtr & camInfoMsg, + const rclcpp::Time & t) +{ + auto ts = _usePubTimestamps ? get_clock()->now() : t; + camInfoMsg->header.stamp = ts; + + if (infoPub) { + if (count_subscribers(infoPub->get_topic_name()) > 0) { + infoPub->publish(*camInfoMsg); + DEBUG_STREAM_VD( + " * Camera Info message published: " << infoPub->get_topic_name()); + DEBUG_STREAM_VD(" * Timestamp: " << ts.nanoseconds() << " nsec"); + } + } +} + +void ZedCameraOne::publishImageWithInfo( + const sl::Mat & img, + const image_transport::Publisher & pubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t) +{ + auto image = sl_tools::imageToROSmsg(img, imgFrameId, t, _usePubTimestamps); + DEBUG_STREAM_VD("Publishing IMAGE message: " << t.nanoseconds() << " nsec"); + try { + publishCameraInfo(infoPub, camInfoMsg, image->header.stamp); + publishCameraInfo(infoPubTrans, camInfoMsg, image->header.stamp); + pubImg.publish(std::move(image)); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM("Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM("Message publishing generic exception: "); + } +} +#ifdef FOUND_ISAAC_ROS_NITROS +void ZedCameraOne::publishImageWithInfo( + const sl::Mat & img, + const nitrosImgPub & nitrosPubImg, + const camInfoPub & infoPub, + const camInfoPub & infoPubTrans, + camInfoMsgPtr & camInfoMsg, + const std::string & imgFrameId, + const rclcpp::Time & t) +{ + DEBUG_STREAM_VD(" * Publishing NITROS IMAGE message: " << t.nanoseconds() << " nsec"); + try { + size_t dpitch = img.getWidthBytes(); + size_t spitch = img.getStepBytes(sl::MEM::GPU); // SL Mat can be padded + + size_t dbuffer_size{spitch * img.getHeight()}; + void * dbuffer; + CUDA_CHECK(cudaMalloc(&dbuffer, dbuffer_size)); + + DEBUG_NITROS("Sent CUDA Image buffer with memory at: %p", dbuffer); + + // Copy data bytes to CUDA buffer + CUDA_CHECK( + cudaMemcpy2D( + dbuffer, + dpitch, + img.getPtr(sl::MEM::GPU), + spitch, + img.getWidth() * img.getPixelBytes(), img.getHeight(), + cudaMemcpyDeviceToDevice)); + + // Adding header data + std_msgs::msg::Header header; + header.stamp = _usePubTimestamps ? get_clock()->now() : t; + header.frame_id = imgFrameId; + + auto encoding = img_encodings::BGRA8; // Default encoding + if (img.getDataType() == sl::MAT_TYPE::U8_C1) { + encoding = img_encodings::MONO8; // Mono image + } else if (img.getDataType() == sl::MAT_TYPE::U8_C3) { + encoding = img_encodings::BGR8; // BGR image + } else if (img.getDataType() == sl::MAT_TYPE::F32_C1) { + encoding = img_encodings::TYPE_32FC1; // Float image + } + + // Create NitrosImage wrapping CUDA buffer + nvidia::isaac_ros::nitros::NitrosImage nitros_image = + nvidia::isaac_ros::nitros::NitrosImageBuilder() + .WithHeader(header) + .WithEncoding(encoding) + .WithDimensions(img.getHeight(), img.getWidth()) + .WithGpuData(dbuffer) + //.WithGpuData(img.getPtr(sl::MEM::GPU)) // TODO: Enable direct GPU memory sharing when supported by Isaac ROS. + .Build(); + + nitrosPubImg->publish(nitros_image); + publishCameraInfo(infoPub, camInfoMsg, header.stamp); + publishCameraInfo(infoPubTrans, camInfoMsg, header.stamp); + } catch (std::system_error & e) { + DEBUG_STREAM_COMM(" * Message publishing exception: " << e.what()); + } catch (...) { + DEBUG_STREAM_COMM(" * Message publishing generic exception: "); + } +} +#endif + +void ZedCameraOne::applyDynamicSettings() +{ + DEBUG_STREAM_COMM("=== Applying dynamic settings ==="); + + if (_debugCommon) { + DEBUG_COMM("Settings to apply: "); + for (auto & param: _camDynParMapChanged) { + if (param.second) {DEBUG_STREAM_COMM(" * " << param.first);} + } + } + + applySaturationSharpnessGamma(); + applyWhiteBalance(); + applyExposure(); + applyAnalogGain(); + applyDigitalGain(); + applyExposureCompensationAndDenoising(); + + DEBUG_COMM("Settings yet to apply: "); + int count = 0; + for (auto & param: _camDynParMapChanged) { + if (param.second) { + count++; + DEBUG_STREAM_COMM(" * " << param.first); + } + } + if (count == 0) { + DEBUG_COMM(" * NONE"); + } + + _triggerUpdateDynParams = (count > 0); + + DEBUG_STREAM_COMM("=== Dynamic settings applied ==="); +} + +// Helper function for saturation, sharpness, gamma +void ZedCameraOne::applySaturationSharpnessGamma() +{ + auto setVideoSetting = [this](sl::VIDEO_SETTINGS setting, int value, + const std::string & settingName) { + if (this->_camDynParMapChanged[settingName]) { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << settingName << ": " + << sl::toString(ret_code)); + } else { + this->_camDynParMapChanged[settingName] = false; + DEBUG_STREAM_COMM("Set " << settingName << " to " << value); + } + } + }; + + setVideoSetting(sl::VIDEO_SETTINGS::SATURATION, _camSaturation, "video.saturation"); + setVideoSetting(sl::VIDEO_SETTINGS::SHARPNESS, _camSharpness, "video.sharpness"); + setVideoSetting(sl::VIDEO_SETTINGS::GAMMA, _camGamma, "video.gamma"); +} + +// Helper function for white balance +void ZedCameraOne::applyWhiteBalance() +{ + auto setVideoSetting = [this](sl::VIDEO_SETTINGS setting, int value, + const std::string & settingName) { + if (this->_camDynParMapChanged[settingName]) { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << settingName << ": " + << sl::toString(ret_code)); + } else { + this->_camDynParMapChanged[settingName] = false; + DEBUG_STREAM_COMM("Set " << settingName << " to " << value); + } + } + }; + + setVideoSetting(sl::VIDEO_SETTINGS::WHITEBALANCE_AUTO, _camAutoWB, "video.auto_whitebalance"); + if (!_camAutoWB) { + setVideoSetting( + sl::VIDEO_SETTINGS::WHITEBALANCE_TEMPERATURE, _camWBTemp * 100, + "video.whitebalance_temperature"); + set_parameter(rclcpp::Parameter("video.auto_whitebalance", false)); + } else { + _camDynParMapChanged["video.whitebalance_temperature"] = false; + } +} + +// Helper function for exposure +void ZedCameraOne::applyExposure() +{ + auto setVideoSetting = [this](sl::VIDEO_SETTINGS setting, int value, + const std::string & settingName) { + if (this->_camDynParMapChanged[settingName]) { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << settingName << ": " + << sl::toString(ret_code)); + } else { + this->_camDynParMapChanged[settingName] = false; + DEBUG_STREAM_COMM("Set " << settingName << " to " << value); + } + } + }; + + auto setVideoSettingRange = [this](sl::VIDEO_SETTINGS setting, int value_min, + int value_max, const std::string & settingName_min, const std::string & settingName_max) { + if (this->_camDynParMapChanged[settingName_min] || + this->_camDynParMapChanged[settingName_max]) + { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value_min, value_max); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting the range of [" + << settingName_min << "," << settingName_max << ": " + << sl::toString(ret_code)); + return false; + } else { + this->_camDynParMapChanged[settingName_min] = false; + this->_camDynParMapChanged[settingName_max] = false; + DEBUG_STREAM_COMM("Set " << settingName_min << " to " << value_min); + DEBUG_STREAM_COMM("Set " << settingName_max << " to " << value_max); + return true; + } + return false; + } + return true; + }; + + if (_camAutoExposure) { + if (_camDynParMapChanged["video.auto_exposure"]) { + set_parameters( + { + rclcpp::Parameter("video.auto_exposure_time_range_min", 28), + rclcpp::Parameter("video.auto_exposure_time_range_max", 30000) + }); + DEBUG_STREAM_COMM("Forced exposure range to [" << 28 << "," << 30000 << "]"); + } + DEBUG_STREAM_COMM( + "Set video.auto_exposure to " + << (_camAutoExposure ? "TRUE" : "FALSE")); + } else { + setVideoSetting( + sl::VIDEO_SETTINGS::EXPOSURE_TIME, _camExpTime, + "video.exposure_time"); + set_parameters( + { + rclcpp::Parameter("video.auto_exposure", false), + rclcpp::Parameter("video.auto_exposure_time_range_min", _camExpTime), + rclcpp::Parameter("video.auto_exposure_time_range_max", _camExpTime) + }); + DEBUG_STREAM_COMM( + "Forced video.auto_exposure to false and exposure range to [" << _camExpTime << "," << + _camExpTime << + "]"); + } + _camDynParMapChanged["video.auto_exposure"] = false; + _camDynParMapChanged["video.exposure_time"] = false; + + if (setVideoSettingRange( + sl::VIDEO_SETTINGS::AUTO_EXPOSURE_TIME_RANGE, + _camAutoExpTimeRangeMin, _camAutoExpTimeRangeMax, + "video.auto_exposure_time_range_min", + "video.auto_exposure_time_range_max")) + { + if (_camAutoExpTimeRangeMin == _camAutoExpTimeRangeMax) { + set_parameters( + { + rclcpp::Parameter("video.auto_exposure", false), + rclcpp::Parameter("video.exposure_time", _camAutoExpTimeRangeMin) + }); + DEBUG_STREAM_COMM( + "Forced video.auto_exposure to false and video.exposure_time to " << + _camAutoExpTimeRangeMin); + } else { + set_parameter(rclcpp::Parameter("video.auto_exposure", true)); + DEBUG_STREAM_COMM("Forced video.auto_exposure to true"); + } + } +} + +// Helper function for analog gain +void ZedCameraOne::applyAnalogGain() +{ + auto setVideoSetting = [this](sl::VIDEO_SETTINGS setting, int value, + const std::string & settingName) { + if (this->_camDynParMapChanged[settingName]) { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << settingName << ": " + << sl::toString(ret_code)); + } else { + this->_camDynParMapChanged[settingName] = false; + DEBUG_STREAM_COMM("Set " << settingName << " to " << value); + } + } + }; + + auto setVideoSettingRange = [this](sl::VIDEO_SETTINGS setting, int value_min, + int value_max, const std::string & settingName_min, const std::string & settingName_max) { + if (this->_camDynParMapChanged[settingName_min] || + this->_camDynParMapChanged[settingName_max]) + { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value_min, value_max); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting the range of [" + << settingName_min << "," << settingName_max << ": " + << sl::toString(ret_code)); + return false; + } else { + this->_camDynParMapChanged[settingName_min] = false; + this->_camDynParMapChanged[settingName_max] = false; + DEBUG_STREAM_COMM("Set " << settingName_min << " to " << value_min); + DEBUG_STREAM_COMM("Set " << settingName_max << " to " << value_max); + return true; + } + return false; + } + return true; + }; + + if (_camAutoAnalogGain) { + if (_camDynParMapChanged["video.auto_analog_gain"]) { + set_parameters( + { + rclcpp::Parameter("video.auto_analog_gain_range_min", 1000), + rclcpp::Parameter("video.auto_analog_gain_range_max", 16000) + }); + DEBUG_STREAM_COMM("Forced analog gain range to [" << 1000 << "," << 16000 << "]"); + } + DEBUG_STREAM_COMM( + "Set video.auto_analog_gain to " + << (_camAutoAnalogGain ? "TRUE" : "FALSE")); + } else { + setVideoSetting( + sl::VIDEO_SETTINGS::ANALOG_GAIN, _camAnalogGain, "video.analog_gain"); + set_parameters( + { + rclcpp::Parameter("video.auto_analog_gain", false), + rclcpp::Parameter("video.auto_analog_gain_range_min", _camAnalogGain), + rclcpp::Parameter("video.auto_analog_gain_range_max", _camAnalogGain) + }); + DEBUG_STREAM_COMM( + "Forced video.auto_analog_gain to false and analog gain range to [" << _camAnalogGain << + "," << _camAnalogGain << + "]"); + } + _camDynParMapChanged["video.auto_analog_gain"] = false; + _camDynParMapChanged["video.analog_gain"] = false; + + if (setVideoSettingRange( + sl::VIDEO_SETTINGS::AUTO_ANALOG_GAIN_RANGE, + _camAutoAnalogGainRangeMin, _camAutoAnalogGainRangeMax, + "video.auto_analog_gain_range_min", + "video.auto_analog_gain_range_max")) + { + if (_camAutoAnalogGainRangeMin == _camAutoAnalogGainRangeMax) { + set_parameters( + { + rclcpp::Parameter("video.auto_analog_gain", false), + rclcpp::Parameter("video.analog_gain", _camAutoAnalogGainRangeMin) + }); + DEBUG_STREAM_COMM( + "Forced video.auto_analog_gain to false and video.analog_gain to " << + _camAutoAnalogGainRangeMin); + } else { + set_parameter(rclcpp::Parameter("video.auto_analog_gain", true)); + DEBUG_STREAM_COMM("Forced video.auto_analog_gain to true"); + } + } +} + +// Helper function for digital gain +void ZedCameraOne::applyDigitalGain() +{ + auto setVideoSetting = [this](sl::VIDEO_SETTINGS setting, int value, + const std::string & settingName) { + if (this->_camDynParMapChanged[settingName]) { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << settingName << ": " + << sl::toString(ret_code)); + } else { + this->_camDynParMapChanged[settingName] = false; + DEBUG_STREAM_COMM("Set " << settingName << " to " << value); + } + } + }; + + auto setVideoSettingRange = [this](sl::VIDEO_SETTINGS setting, int value_min, + int value_max, const std::string & settingName_min, const std::string & settingName_max) { + if (this->_camDynParMapChanged[settingName_min] || + this->_camDynParMapChanged[settingName_max]) + { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value_min, value_max); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting the range of [" + << settingName_min << "," << settingName_max << ": " + << sl::toString(ret_code)); + return false; + } else { + this->_camDynParMapChanged[settingName_min] = false; + this->_camDynParMapChanged[settingName_max] = false; + DEBUG_STREAM_COMM("Set " << settingName_min << " to " << value_min); + DEBUG_STREAM_COMM("Set " << settingName_max << " to " << value_max); + return true; + } + return false; + } + return true; + }; + + if (_camAutoDigitalGain) { + if (_camDynParMapChanged["video.auto_digital_gain"]) { + set_parameters( + { + rclcpp::Parameter("video.auto_digital_gain_range_min", 1), + rclcpp::Parameter("video.auto_digital_gain_range_max", 256) + }); + DEBUG_STREAM_COMM("Forced digital gain range to [" << 1 << "," << 256 << "]"); + } + DEBUG_STREAM_COMM( + "Set video.auto_digital_gain to " + << (_camAutoDigitalGain ? "TRUE" : "FALSE")); + } else { + setVideoSetting( + sl::VIDEO_SETTINGS::DIGITAL_GAIN, _camDigitalGain, "video.digital_gain"); + set_parameters( + { + rclcpp::Parameter("video.auto_digital_gain", false), + rclcpp::Parameter("video.auto_digital_gain_range_min", _camDigitalGain), + rclcpp::Parameter("video.auto_digital_gain_range_max", _camDigitalGain) + }); + DEBUG_STREAM_COMM( + "Forced video.auto_digital_gain to false and digital gain range to [" << _camDigitalGain << + "," << _camDigitalGain << + "]"); + } + _camDynParMapChanged["video.auto_digital_gain"] = false; + _camDynParMapChanged["video.digital_gain"] = false; + + if (setVideoSettingRange( + sl::VIDEO_SETTINGS::AUTO_DIGITAL_GAIN_RANGE, + _camAutoDigitalGainRangeMin, _camAutoDigitalGainRangeMax, + "video.auto_digital_gain_range_min", + "video.auto_digital_gain_range_max")) + { + if (_camAutoDigitalGainRangeMin == _camAutoDigitalGainRangeMax) { + set_parameters( + { + rclcpp::Parameter("video.auto_digital_gain", false), + rclcpp::Parameter("video.digital_gain", _camAutoDigitalGainRangeMin) + }); + DEBUG_STREAM_COMM( + "Forced video.auto_digital_gain to false and video.digital_gain to " << + _camAutoDigitalGainRangeMin); + } else { + set_parameter(rclcpp::Parameter("video.auto_digital_gain", true)); + DEBUG_STREAM_COMM("Forced video.auto_digital_gain to true"); + } + } +} + +// Helper function for exposure compensation and denoising +void ZedCameraOne::applyExposureCompensationAndDenoising() +{ + auto setVideoSetting = [this](sl::VIDEO_SETTINGS setting, int value, + const std::string & settingName) { + if (this->_camDynParMapChanged[settingName]) { + sl::ERROR_CODE ret_code = _zed->setCameraSettings(setting, value); + if (ret_code != sl::ERROR_CODE::SUCCESS) { + RCLCPP_WARN_STREAM( + get_logger(), "Error setting " + << settingName << ": " + << sl::toString(ret_code)); + } else { + this->_camDynParMapChanged[settingName] = false; + DEBUG_STREAM_COMM("Set " << settingName << " to " << value); + } + } + }; + + setVideoSetting( + sl::VIDEO_SETTINGS::EXPOSURE_COMPENSATION, _camExposureComp, + "video.exposure_compensation"); + + setVideoSetting(sl::VIDEO_SETTINGS::DENOISING, _camDenoising, "video.denoising"); +} + +void ZedCameraOne::publishCameraInfos() +{ + rclcpp::Time pub_ts = get_clock()->now(); + + publishCameraInfo(_pubColorImgInfo, _camInfoMsg, pub_ts); + publishCameraInfo(_pubColorRawImgInfo, _camInfoRawMsg, pub_ts); + publishCameraInfo(_pubGrayImgInfo, _camInfoMsg, pub_ts); + publishCameraInfo(_pubGrayRawImgInfo, _camInfoRawMsg, pub_ts); + publishCameraInfo(_pubColorImgInfoTrans, _camInfoMsg, pub_ts); + publishCameraInfo(_pubColorRawImgInfoTrans, _camInfoRawMsg, pub_ts); + publishCameraInfo(_pubGrayImgInfoTrans, _camInfoMsg, pub_ts); + publishCameraInfo(_pubGrayRawImgInfoTrans, _camInfoRawMsg, pub_ts); +} + +} diff --git a/src/lib/zed-ros2-wrapper/zed_debug/CMakeLists.txt b/src/lib/zed-ros2-wrapper/zed_debug/CMakeLists.txt new file mode 100644 index 0000000000..52a131f59a --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/CMakeLists.txt @@ -0,0 +1,163 @@ +cmake_minimum_required(VERSION 3.8) +project(zed_debug) + +################################################ +## Generate symbols for IDE indexer (VSCode) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +################################################ +# Check the ROS2 version + +set(ROS2_FOUND FALSE) +if(DEFINED ENV{ROS_DISTRO}) + set(FOUND_ROS2_DISTRO $ENV{ROS_DISTRO}) + set(ROS2_FOUND TRUE) + #message("* Found ROS2 ${FOUND_ROS2_DISTRO}") +else() + message("* ROS2 distro variable not set. Trying to figure it out...") + set(ROS2_DISTROS "ardent;bouncy;crystal;dashing;eloquent;foxy;galactic;humble;iron;jazzy;kilted;rolling") + set(ROS2_FOUND FALSE) + foreach(distro ${ROS2_DISTROS}) + if(NOT ROS2_FOUND) + find_path(RCLCPP_H rclcpp.hpp PATHS /opt/ros/${distro}/include/rclcpp) + if(RCLCPP_H) + #message("* Found ROS2 ${distro}") + set(FOUND_ROS2_DISTRO ${distro}) + set(ROS2_FOUND TRUE) + endif() + endif() + endforeach() +endif() + +if(ROS2_FOUND) + if(${FOUND_ROS2_DISTRO} STREQUAL "foxy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_FOXY) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "humble") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_HUMBLE) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "iron") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_IRON) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "jazzy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_JAZZY) + else() + message("*** WARNING *** Unsupported ROS2 ${FOUND_ROS2_DISTRO}. '${PROJECT_NAME}' may not work correctly.") + endif() +else() + message("*** WARNING *** ROS2 distro is unknown. This package could not work correctly.") +endif() +################################################ + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++17 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + #message(" * Release with Debug Info Mode") + add_compile_options(-Wno-deprecated-declarations) +endif() + +if(CMAKE_BUILD_TYPE MATCHES Debug) + message(" * Debug Mode") +endif() + +############################################# +# Dependencies +find_package(ZED REQUIRED) + +exec_program(uname ARGS -p OUTPUT_VARIABLE CMAKE_SYSTEM_NAME2) +if(CMAKE_SYSTEM_NAME2 MATCHES "aarch64") # Jetson TX + set(CUDA_USE_STATIC_CUDA_RUNTIME OFF) +endif() + +find_package(CUDA REQUIRED) + +set(DEPENDENCIES + rclcpp + rclcpp_components + zed_components + backward_ros +) + +find_package(ament_cmake_auto REQUIRED) +ament_auto_find_build_dependencies() + +find_package(rcutils REQUIRED) +find_package(rclcpp REQUIRED) +find_package(rclcpp_components REQUIRED) +find_package(zed_components REQUIRED) + +# Debugging with backward-cpp +find_package(backward_ros REQUIRED) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + ament_lint_auto_find_test_dependencies() +endif() + +############################################################################### +#Add all files in subdirectories of the project in +# a dummy_target so qtcreator have access to all files +file(GLOB_RECURSE all_files ${CMAKE_SOURCE_DIR}/*) +add_custom_target(all_${PROJECT_NAME}_files SOURCES ${all_files}) + +############################################################################### +# LIBS + +link_directories(${ZED_LIBRARY_DIR}) +link_directories(${CUDA_LIBRARY_DIRS}) + +set(ZED_LIBS + ${ZED_LIBRARIES} + ${CUDA_LIBRARIES} +) + +############################################################################### +# SOURCES +set(ZED_DEBUG_PROC + ${CMAKE_CURRENT_SOURCE_DIR}/src/zed_debug_proc.cpp +) + +############################################################################### +# Bin and Install + +# ZED DEBUG PROC executable +add_executable(zed_debug_proc + ${ZED_DEBUG_PROC} +) +target_include_directories(zed_debug_proc PUBLIC + ${CUDA_INCLUDE_DIRS} + ${ZED_INCLUDE_DIRS} +) +target_link_directories(zed_debug_proc PUBLIC + ${CUDA_LIBRARY_DIRS} +) +target_link_libraries(zed_debug_proc + ${CUDA_LIBRARIES} +) +ament_target_dependencies(zed_debug_proc + ${DEPENDENCIES} +) + +# Install executable +install(TARGETS zed_debug_proc + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION lib/${PROJECT_NAME} +) + +# Install LAUNCH and CONFIG files +install(DIRECTORY + launch config + DESTINATION share/${PROJECT_NAME} +) + +ament_package() diff --git a/src/lib/zed-ros2-wrapper/zed_debug/README.md b/src/lib/zed-ros2-wrapper/zed_debug/README.md new file mode 100644 index 0000000000..a151a97a5e --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/README.md @@ -0,0 +1,97 @@ +# ZED ROS2 Wrapper Debugging + +## Build with Debug Symbols + +Go to the root of your ROS2 workspace. + +Clean the previous build if they do not contain debug symbols: + +```bash +rm -rf install +rm -rf build +rm -rf logs +``` + +Build the ZED ROS2 wrapper with debug symbols: + +```bash +colcon build --symlink-install --cmake-args=-DCMAKE_BUILD_TYPE=Debug --parallel-workers $(nproc) +``` + +or use `RelWithDebInfo` build type for optimized builds with debug symbols (normally required by the ZED SDK): + +```bash +colcon build --symlink-install --cmake-args=-DCMAKE_BUILD_TYPE=RelWithDebInfo --parallel-workers $(nproc) +``` + +## Debug with VSCode + +It's possible to debug the ZED ROS2 nodes using VSCode and the `ros2 launch` command with a `gdbserver` prefix. + +### Setup VSCode launch configuration + +1) Open VSCode on your workspace. +2) Go to your side bar, 'Run and Debug' section. +3) Add a new configuration by clicking on 'create a launch.json file'. +4) Select 'C++ (GDB/LLDB)'. +5) Replace the content of the generated `launch.json` file with the following: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C++ Debugger", + "request": "launch", + "type": "cppdbg", + "miDebuggerServerAddress": "localhost:3000", + "cwd": "${workspaceFolder}", + "program": "install/zed_debug/lib/zed_debug/zed_debug_proc", + "stopAtEntry": true + } + ] +} +``` + +with `"stopAtEntry": true` the node will stop at the beginning of the `main` function. This allows you to set breakpoints before the execution continues. + +Learn more about VSCode debugging configuration: + +* [Debug C++ in Visual Studio Code](https://code.visualstudio.com/docs/cpp/cpp-debug) +* [Configure C/C++ debugging](https://code.visualstudio.com/docs/cpp/launch-json-reference) + +### Start the node with gdbserver + +The `zed_camera_debug.launch.py` launch file has been modified to accept a `cmd_prefix` argument that allows you to add a prefix to the node executable. + +Run the launch file with the `gdbserver` prefix: + +```bash +ros2 launch zed_debug zed_camera_debug.launch.py camera_model:= cmd_prefix:='gdbserver localhost:3000' +``` + +## Debug with `GDB` + +You can also debug the ZED ROS2 nodes using `gdb` directly from the command line. + +```bash +ros2 launch zed_debug zed_camera_debug.launch.py camera_model:= cmd_prefix:='gdb --args' +``` + +You can modify `gdb --args` to add any other `gdb` options you may need. + +## Debug with `Valgrind` + +You can also run the ZED ROS2 nodes with `valgrind` to check for memory leaks and other memory-related issues. + +Run the launch file with the `valgrind` prefix: + +```bash +ros2 launch zed_debug zed_camera_debug.launch.py camera_model:= cmd_prefix:='valgrind --leak-check=full --track-origins=yes' +``` + +You can modify `valgrind --leak-check=full --track-origins=yes` to add any other `valgrind` options you may need. + +## Known Issues + +When the `isaac_ros_managed_nitros` package is installed and the ZED Camera Components are linked against Isaac ROS libraries, you may experience issues when trying to start the `zed_debug` executable. This appears to be an issue with the Isaac ROS libraries when used with static ROS 2 Composition instead of dynamic composition (using launch files). We are working with NVIDIA to resolve this issue. In the meantime, if you encounter this problem and want to debug the ZED Components, please uninstall the `isaac_ros_managed_nitros` package from your system and rebuild. diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/common_mono.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/common_mono.yaml new file mode 100644 index 0000000000..ae9f0e21e5 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/common_mono.yaml @@ -0,0 +1,84 @@ +# config/common_mono.yaml +# Common parameters to Stereolabs ZED Stereo cameras + +--- +/**: + ros__parameters: + general: + serial_number: 0 # overwritten by launch file + pub_resolution: "CUSTOM" # The resolution used for output. 'NATIVE' to use the same `general.grab_resolution` - `CUSTOM` to apply the `general.pub_downscale_factor` downscale factory to reduce bandwidth in transmission + pub_downscale_factor: 2.0 # rescale factor used to rescale image before publishing when 'pub_resolution' is 'CUSTOM' + gpu_id: -1 + optional_opencv_calibration_file: "" # Optional path where the ZED SDK can find a file containing the calibration information of the camera computed by OpenCV. Read the ZED SDK documentation for more information: https://www.stereolabs.com/docs/api/structsl_1_1InitParameters.html#a9eab2753374ef3baec1d31960859ba19 + publish_status: true # Enable/Disable the publishing of the camera status topic + + svo: + decryption_key: "" # Optional decryption key/passphrase when opening encrypted SVO files + use_svo_timestamps: true # Use the SVO timestamps to publish data. If false, data will be published at the system time. + publish_svo_clock: true # [overwritten by launch file options] When use_svo_timestamps is true allows to publish the SVO clock to the `/clock` topic. This is useful for synchronous rosbag playback. + svo_loop: false # Enable loop mode when using an SVO as input source. NOTE: ignored if SVO timestamping is used + svo_realtime: true # if true the SVO will be played trying to respect the original framerate eventually skipping frames, otherwise every frame will be processed respecting the `pub_frame_rate` setting + play_from_frame: 0 # Start playing the SVO from a specific frame + + video: + saturation: 4 # [DYNAMIC] + sharpness: 4 # [DYNAMIC] + gamma: 8 # [DYNAMIC] + auto_whitebalance: true # [DYNAMIC] + whitebalance_temperature: 42 # [DYNAMIC] - [28,65] x100 - works only if `auto_whitebalance` is false + auto_exposure: true # [DYNAMIC] - Enables or disables auto exposure control. false: manual, true: auto + exposure_time: 16000 # [DYNAMIC] - Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # [DYNAMIC] - Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # [DYNAMIC] - Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # [DYNAMIC] - Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + auto_analog_gain: true # [DYNAMIC] - Enables or disables auto gain control. false: manual, true: auto + analog_gain: 1255 # [DYNAMIC] - Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # [DYNAMIC] - Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # [DYNAMIC] - Defines the maximum range of sensor gain in automatic control + auto_digital_gain: false # [DYNAMIC] - Enables or disables auto digital gain control. false: manual, true: auto + digital_gain: 1 # [DYNAMIC] - Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # [DYNAMIC] - Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # [DYNAMIC] - Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # [DYNAMIC] - Defines the level of denoising applied on both left and right images. Range [0-100] + enable_24bit_output: false # [SDK >= 5.1] Enable BGR 24-bit output for lower bandwidth usage. If false, BGRA 32-bit output is used (old way before SDK v5.1) + publish_rgb: true # Advertise the RGB image topics that are published only if a node subscribes to them + publish_gray: false # Advertise the gray image topics that are published only if a node subscribes to them + publish_raw: false # Advertise the raw image topics that are published only if a node subscribes to them (only if 'publish_rgb' or 'publish_gray' is true) + + sensors: + publish_imu_tf: true # [overwritten by launch file options] enable/disable the IMU TF broadcasting + sensors_pub_rate: 100. # [DYNAMIC] - frequency of publishing of sensors data. MAX: 400. - MIN: grab rate + publish_imu: true # Advertise the IMU topic that is published only if a node subscribes to it + publish_imu_raw: false # Advertise the raw IMU topic that is published only if a node subscribes to it + publish_cam_imu_transf: false # Advertise the CAMERA-IMU transformation topic that is published only if a node subscribes to it + publish_temp: false # Advertise the temperature topics that are published only if a node subscribes to them + + stream_server: + stream_enabled: false # enable the streaming server when the camera is open + codec: 'H264' # different encoding types for image streaming: 'H264', 'H265' + port: 30000 # Port used for streaming. Port must be an even number. Any odd number will be rejected. + bitrate: 12500 # [1000 - 60000] Streaming bitrate (in Kbits/s) used for streaming. See https://www.stereolabs.com/docs/api/structsl_1_1StreamingParameters.html#a873ba9440e3e9786eb1476a3bfa536d0 + gop_size: -1 # [max 256] The GOP size determines the maximum distance between IDR/I-frames. Very high GOP size will result in slightly more efficient compression, especially on static scenes. But latency will increase. + adaptative_bitrate: false # Bitrate will be adjusted depending the number of packet dropped during streaming. If activated, the bitrate can vary between [bitrate/4, bitrate]. + chunk_size: 16084 # [1024 - 65000] Stream buffers are divided into X number of chunks where each chunk is chunk_size bytes long. You can lower chunk_size value if network generates a lot of packet lost: this will generates more chunk for a single image, but each chunk sent will be lighter to avoid inside-chunk corruption. Increasing this value can decrease latency. + target_framerate: 0 # Framerate for the streaming output. This framerate must be below or equal to the camera framerate. Allowed framerates are 15, 30, 60 or 100 if possible. Any other values will be discarded and camera FPS will be taken. + + advanced: # WARNING: do not modify unless you are confident of what you are doing + # Reference documentation: https://man7.org/linux/man-pages/man7/sched.7.html + thread_sched_policy: "SCHED_BATCH" # 'SCHED_OTHER', 'SCHED_BATCH', 'SCHED_FIFO', 'SCHED_RR' - NOTE: 'SCHED_FIFO' and 'SCHED_RR' require 'sudo' + thread_grab_priority: 50 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + thread_sensor_priority: 70 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + + debug: + sdk_verbose: 1 # Set the verbose level of the ZED SDK + sdk_verbose_log_file: '' # Path to the file where the ZED SDK will log its messages. If empty, no file will be created. The log level can be set using the `sdk_verbose` parameter. + use_pub_timestamps: false # Use the current ROS time for the message timestamp instead of the camera timestamp. This is useful to test data communication latency. + debug_common: false + debug_dyn_params: false + debug_video_depth: false + debug_camera_controls: false + debug_sensors: false + debug_streaming: false + debug_advanced: false + debug_nitros: false + disable_nitros: false # If available, disable NITROS usage for debugging and testing purposes diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/common_stereo.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/common_stereo.yaml new file mode 100644 index 0000000000..c45eb95d3f --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/common_stereo.yaml @@ -0,0 +1,220 @@ +# config/common_stereo.yaml +# Common parameters to Stereolabs ZED Stereo cameras + +--- +/**: + ros__parameters: + use_sim_time: false # Set to `true` only if there is a publisher for the simulated clock to the `/clock` topic. Normally used in simulation mode. + + simulation: + sim_enabled: false # Set to `true` to enable the simulation mode and connect to a simulation server + sim_address: '127.0.0.1' # The connection address of the simulation server. See the documentation of the supported simulation plugins for more information. + sim_port: 30000 # The connection port of the simulation server. See the documentation of the supported simulation plugins for more information. + + svo: + decryption_key: "" # Optional decryption key/passphrase when opening encrypted SVO files + use_svo_timestamps: true # Use the SVO timestamps to publish data. If false, data will be published at the system time. + publish_svo_clock: false # [overwritten by launch file options] When use_svo_timestamps is true allows to publish the SVO clock to the `/clock` topic. This is useful for synchronous rosbag playback. + svo_loop: false # Enable loop mode when using an SVO as input source. NOTE: ignored if SVO timestamping is used + svo_realtime: false # if true the SVO will be played trying to respect the original framerate eventually skipping frames, otherwise every frame will be processed respecting the `pub_frame_rate` setting + play_from_frame: 0 # Start playing the SVO from a specific frame + replay_rate: 1.0 # Replay rate for the SVO when not used in realtime mode (between [0.10-5.0]) + + general: + camera_timeout_sec: 5 + camera_max_reconnect: 5 + camera_flip: false + self_calib: true # Enable the self-calibration process at camera opening. See https://www.stereolabs.com/docs/api/structsl_1_1InitParameters.html#affeaa06cfc1d849e311e484ceb8edcc5 + serial_number: 0 # overwritten by launch file + pub_resolution: 'CUSTOM' # The resolution used for image and depth map publishing. 'NATIVE' to use the same `general.grab_resolution` - `CUSTOM` to apply the `general.pub_downscale_factor` downscale factory to reduce bandwidth in transmission + pub_downscale_factor: 2.0 # rescale factor used to rescale image before publishing when 'pub_resolution' is 'CUSTOM' + pub_frame_rate: 15.0 # [DYNAMIC] Frequency of publishing of visual images and depth data (not the Point Cloud, see 'depth.point_cloud_freq'). This value must be equal or less than the camera framerate. + enable_image_validity_check: 1 # [SDK5 required] Sets the image validity check. If set to 1, the SDK will check if the frames are valid before processing. + gpu_id: -1 + optional_opencv_calibration_file: '' # Optional path where the ZED SDK can find a file containing the calibration information of the camera computed by OpenCV. Read the ZED SDK documentation for more information: https://www.stereolabs.com/docs/api/structsl_1_1InitParameters.html#a9eab2753374ef3baec1d31960859ba19 + async_image_retrieval: false # If set to true will camera image retrieve at a framerate different from \ref grab() application framerate. This is useful for recording SVO or sending camera stream at different rate than application. + publish_status: true # Advertise the status topics that are published only if a node subscribes to them + # Other parameters are defined, according to the camera model, in the 'zed.yaml', 'zedm.yaml', 'zed2.yaml', 'zed2i.yaml' + # 'zedx.yaml', 'zedxmini.yaml', 'virtual.yaml' files + + video: + saturation: 4 # [DYNAMIC] + sharpness: 4 # [DYNAMIC] + gamma: 8 # [DYNAMIC] + auto_exposure_gain: true # [DYNAMIC] + exposure: 80 # [DYNAMIC] + gain: 80 # [DYNAMIC] + auto_whitebalance: true # [DYNAMIC] + whitebalance_temperature: 42 # [DYNAMIC] - [28,65] x100 - works only if `auto_whitebalance` is false + enable_24bit_output: false # [SDK >= 5.1] Enable BGR 24-bit output for lower bandwidth usage. If false, BGRA 32-bit output is used (old way before SDK v5.1) + publish_rgb: true # Advertise the RGB image topics that are published only if a node subscribes to them + publish_left_right: false # Advertise the left and right image topics that are published only if a node subscribes to them + publish_raw: false # Advertise the raw image topics that are published only if a node subscribes to them + publish_gray: false # Advertise the gray image topics that are published only if a node subscribes to them + publish_stereo: false # Advertise the stereo image topic that is published only if a node subscribes to it + # Other parameters are defined, according to the camera model, in the 'zed.yaml', 'zedm.yaml', 'zed2.yaml', 'zed2i.yaml' + # 'zedx.yaml', 'zedxmini.yaml', 'virtual.yaml' files + + sensors: + publish_imu_tf: false # [overwritten by launch file options] enable/disable the IMU TF broadcasting + sensors_image_sync: false # Synchronize Sensors messages with latest published video/depth message + sensors_pub_rate: 100. # frequency of publishing of sensors data. MAX: 400. - MIN: grab rate + publish_imu: false # Advertise the IMU topic that is published only if a node subscribes to it + publish_imu_raw: false # Advertise the raw IMU topic that is published only if a node subscribes to it + publish_cam_imu_transf: false # Advertise the CAMERA-IMU transformation topic that is published only if a node subscribes to it + publish_mag: false # Advertise the magnetometer topic that is published only if a node subscribes to it + publish_baro: false # Advertise the barometer topic that is published only if a node subscribes to it + publish_temp: false # Advertise the temperature topics that are published only if a node subscribes to them + + region_of_interest: + automatic_roi: false # Enable the automatic ROI generation to automatically detect part of the robot in the FoV and remove them from the processing. Note: if enabled the value of `manual_polygon` is ignored + depth_far_threshold_meters: 2.5 # Filtering how far object in the ROI should be considered, this is useful for a vehicle for instance + image_height_ratio_cutoff: 0.5 # By default consider only the lower half of the image, can be useful to filter out the sky + #manual_polygon: '[]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + #manual_polygon: '[[0.25,0.33],[0.75,0.33],[0.75,0.5],[0.5,0.75],[0.25,0.5]]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + #manual_polygon: '[[0.25,0.25],[0.75,0.25],[0.75,0.75],[0.25,0.75]]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + #manual_polygon: '[[0.5,0.25],[0.75,0.5],[0.5,0.75],[0.25,0.5]]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + apply_to_depth: true # Apply ROI to depth processing + apply_to_positional_tracking: true # Apply ROI to positional tracking processing + apply_to_object_detection: true # Apply ROI to object detection processing + apply_to_body_tracking: true # Apply ROI to body tracking processing + apply_to_spatial_mapping: true # Apply ROI to spatial mapping processing + publish_roi_mask: false # Advertise the ROI mask image topic that is published only if a node subscribes to it + + depth: + depth_mode: 'NEURAL_LIGHT' # Matches the ZED SDK setting: 'NONE', 'NEURAL_LIGHT', 'NEURAL', 'NEURAL_PLUS' - Note: if 'NONE' all the modules that requires depth extraction are disabled by default (Pos. Tracking, Obj. Detection, Mapping, ...) + depth_stabilization: 30 # Forces positional tracking to start if major than 0 - Range: [0,100] + openni_depth_mode: false # 'false': 32bit float [meters], 'true': 16bit unsigned int [millimeters] + point_cloud_freq: 10.0 # [DYNAMIC] Frequency of the pointcloud publishing. This value must be equal or less than the camera framerate. + point_cloud_res: 'COMPACT' # The resolution used for point cloud publishing - 'COMPACT'-Standard resolution. Optimizes processing and bandwidth, 'REDUCED'-Half resolution. Low processing and bandwidth requirements + depth_confidence: 95 # [DYNAMIC] + depth_texture_conf: 100 # [DYNAMIC] + remove_saturated_areas: true # [DYNAMIC] + publish_depth_map: true # Advertise the depth map topics that are published only if a node subscribes to them + publish_depth_info: false # Advertise the depth info topic that is published only if a node subscribes to it + publish_point_cloud: true # Advertise the point cloud topic that is published only if a node subscribes to it + publish_depth_confidence: false # Advertise the depth confidence topic that is published only if a node subscribes to it + publish_disparity: false # Advertise the disparity topic that is published only if a node subscribes to it + # Other parameters are defined, according to the camera model, in the 'zed.yaml', 'zedm.yaml', 'zed2.yaml', 'zed2i.yaml' + # 'zedx.yaml', 'zedxmini.yaml', 'virtual.yaml' files + + pos_tracking: + pos_tracking_enabled: true # True to enable positional tracking from start + pos_tracking_mode: 'GEN_3' # Matches the ZED SDK setting: 'GEN_1', 'GEN_2', 'GEN_3' + imu_fusion: true # enable/disable IMU fusion. When set to false, only the optical odometry will be used. + publish_tf: true # [overwritten by launch file options] publish `odom -> camera_link` TF + publish_map_tf: true # [overwritten by launch file options] publish `map -> odom` TF + map_frame: 'map' + odometry_frame: 'odom' + area_memory: true # Enable to detect loop closure + area_file_path: '' # Path to the area memory file for relocalization and loop closure in a previously explored environment. + enable_localization_only: false # If true, the camera will only localize in the loaded area memory without updating the map with new information. + save_area_memory_on_closing: false # Save Area memory before closing the camera if `area_file_path` is not empty. You can also use the `save_area_memory` service to save the area memory at any time. + reset_odom_with_loop_closure: true # Re-initialize odometry to the last valid pose when loop closure happens (reset camera odometry drift) + publish_3d_landmarks: false # Publish 3D landmarks used by the positional tracking algorithm + publish_lm_skip_frame: 5 # Publish the landmarks every X frames to reduce bandwidth. Set to 0 to publish all landmarks + depth_min_range: 0.0 # Set this value for removing fixed zones of the robot in the FoV of the camerafrom the visual odometry evaluation + set_as_static: false # If 'true' the camera will be static and not move in the environment + set_gravity_as_origin: true # If 'true' align the positional tracking world to imu gravity measurement. Keep the yaw from the user initial pose. + floor_alignment: false # Enable to automatically calculate camera/floor offset + initial_base_pose: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # Initial position of the `camera_link` frame in the map -> [X, Y, Z, R, P, Y] + path_pub_rate: 2.0 # [DYNAMIC] - Camera trajectory publishing frequency + path_max_count: -1 # use '-1' for unlimited path size + two_d_mode: false # Force navigation on a plane. If true the Z value will be fixed to 'fixed_z_value', roll and pitch to zero + fixed_z_value: 0.0 # Value to be used for Z coordinate if `two_d_mode` is true + transform_time_offset: 0.0 # The value added to the timestamp of `map->odom` and `odom->camera_link` transform being generated + reset_pose_with_svo_loop: true # Reset the camera pose the `initial_base_pose` when the SVO loop is enabled and the SVO playback reaches the end of the file. + publish_odom_pose: true # Advertise the odometry and pose topics that are published only if a node subscribes to them + publish_pose_cov: false # Advertise the pose with covariance topic that is published only if a node subscribes to it + publish_cam_path: false # Advertise the camera odometry and pose path topics that are published only if a node subscribes to them + + gnss_fusion: + gnss_fusion_enabled: false # fuse 'sensor_msg/NavSatFix' message information into pose data + gnss_fix_topic: '/fix' # Name of the GNSS topic of type NavSatFix to subscribe [Default: '/gps/fix'] + gnss_zero_altitude: false # Set to `true` to ignore GNSS altitude information + h_covariance_mul: 1.0 # Multiplier factor to be applied to horizontal covariance of the received fix (plane X/Y) + v_covariance_mul: 1.0 # Multiplier factor to be applied to vertical covariance of the received fix (Z axis) + publish_utm_tf: true # Publish `utm` -> `map` TF + broadcast_utm_transform_as_parent_frame: false # if 'true' publish `utm` -> `map` TF, otherwise `map` -> `utm` + enable_reinitialization: false # determines whether reinitialization should be performed between GNSS and VIO fusion when a significant disparity is detected between GNSS data and the current fusion data. It becomes particularly crucial during prolonged GNSS signal loss scenarios. + enable_rolling_calibration: true # If this parameter is set to true, the fusion algorithm will used a rough VIO / GNSS calibration at first and then refine it. This allow you to quickly get a fused position. + enable_translation_uncertainty_target: false # When this parameter is enabled (set to true), the calibration process between GNSS and VIO accounts for the uncertainty in the determined translation, thereby facilitating the calibration termination. The maximum allowable uncertainty is controlled by the 'target_translation_uncertainty' parameter. + gnss_vio_reinit_threshold: 5.0 # determines the threshold for GNSS/VIO reinitialization. If the fused position deviates beyond out of the region defined by the product of the GNSS covariance and the gnss_vio_reinit_threshold, a reinitialization will be triggered. + target_translation_uncertainty: 0.1 # defines the target translation uncertainty at which the calibration process between GNSS and VIO concludes. By default, the threshold is set at 10 centimeters. + target_yaw_uncertainty: 0.1 # defines the target yaw uncertainty at which the calibration process between GNSS and VIO concludes. The unit of this parameter is in radian. By default, the threshold is set at 0.1 radians. + + mapping: + mapping_enabled: false # True to enable mapping t # Pand fused point cloud pubblication + resolution: 0.05 # maps resolution in meters [min: 0.01f - max: 0.2f] + max_mapping_range: 5.0 # maximum depth range while mapping in meters (-1 for automatic calculation) [2.0, 20.0] + fused_pointcloud_freq: 1.0 # frequency of the publishing of the fused colored point cloud + clicked_point_topic: '/clicked_point' # Topic published by Rviz when a point of the cloud is clicked. Used for plane detection + pd_max_distance_threshold: 0.15 # Plane detection: controls the spread of plane by checking the position difference. + pd_normal_similarity_threshold: 15.0 # Plane detection: controls the spread of plane by checking the angle difference. + publish_det_plane: false # Advertise the plane detection topics that is published only if a node subscribes to it + + object_detection: + od_enabled: false # True to enable Object Detection + enable_tracking: true # Whether the object detection system includes object tracking capabilities across a sequence of images. + detection_model: 'MULTI_CLASS_BOX_FAST' # 'MULTI_CLASS_BOX_FAST', 'MULTI_CLASS_BOX_MEDIUM', 'MULTI_CLASS_BOX_ACCURATE', 'PERSON_HEAD_BOX_FAST', 'PERSON_HEAD_BOX_ACCURATE', 'CUSTOM_YOLOLIKE_BOX_OBJECTS' + max_range: 20.0 # [m] Upper depth range for detections.The value cannot be greater than 'depth.max_depth' + filtering_mode: 'NMS3D' # Filtering mode that should be applied to raw detections: 'NONE', 'NMS3D', 'NMS3D_PER_CLASS' + prediction_timeout: 2.0 # During this time [sec], the object will have OK state even if it is not detected. Set this parameter to 0 to disable SDK predictions + allow_reduced_precision_inference: false # Allow inference to run at a lower precision to improve runtime and memory usage + # Other parameters are defined in the 'object_detection.yaml' and 'custom_object_detection.yaml' files + + body_tracking: + bt_enabled: false # True to enable Body Tracking + model: 'HUMAN_BODY_MEDIUM' # 'HUMAN_BODY_FAST', 'HUMAN_BODY_MEDIUM', 'HUMAN_BODY_ACCURATE' + body_format: 'BODY_38' # 'BODY_18','BODY_34','BODY_38' + allow_reduced_precision_inference: false # Allow inference to run at a lower precision to improve runtime and memory usage + max_range: 15.0 # [m] Defines a upper depth range for detections + body_kp_selection: 'FULL' # 'FULL', 'UPPER_BODY' + enable_body_fitting: false # Defines if the body fitting will be applied + enable_tracking: true # Defines if the object detection will track objects across images flow + prediction_timeout_s: 0.5 # During this time [sec], the skeleton will have OK state even if it is not detected. Set this parameter to 0 to disable SDK predictions + confidence_threshold: 50.0 # [DYNAMIC] - Minimum value of the detection confidence of skeleton key points [0,99] + minimum_keypoints_threshold: 5 # [DYNAMIC] - Minimum number of skeleton key points to be detected for a valid skeleton + + stream_server: + stream_enabled: false # enable the streaming server when the camera is open + codec: 'H264' # different encoding types for image streaming: 'H264', 'H265' + port: 30000 # Port used for streaming. Port must be an even number. Any odd number will be rejected. + bitrate: 12500 # [1000 - 60000] Streaming bitrate (in Kbits/s) used for streaming. See https://www.stereolabs.com/docs/api/structsl_1_1StreamingParameters.html#a873ba9440e3e9786eb1476a3bfa536d0 + gop_size: -1 # [max 256] The GOP size determines the maximum distance between IDR/I-frames. Very high GOP size will result in slightly more efficient compression, especially on static scenes. But latency will increase. + adaptative_bitrate: false # Bitrate will be adjusted depending the number of packet dropped during streaming. If activated, the bitrate can vary between [bitrate/4, bitrate]. + chunk_size: 16084 # [1024 - 65000] Stream buffers are divided into X number of chunks where each chunk is chunk_size bytes long. You can lower chunk_size value if network generates a lot of packet lost: this will generates more chunk for a single image, but each chunk sent will be lighter to avoid inside-chunk corruption. Increasing this value can decrease latency. + target_framerate: 0 # Framerate for the streaming output. This framerate must be below or equal to the camera framerate. Allowed framerates are 15, 30, 60 or 100 if possible. Any other values will be discarded and camera FPS will be taken. + + advanced: # WARNING: do not modify unless you are confident of what you are doing + # Reference documentation: https://man7.org/linux/man-pages/man7/sched.7.html + change_thread_priority: false # Enable changing thread priority and scheduling policy + thread_sched_policy: 'SCHED_BATCH' # 'SCHED_OTHER', 'SCHED_BATCH', 'SCHED_FIFO', 'SCHED_RR' - NOTE: 'SCHED_FIFO' and 'SCHED_RR' require 'sudo' + thread_grab_priority: 50 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + thread_sensor_priority: 70 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + thread_pointcloud_priority: 60 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + + debug: + sdk_verbose: 1 # Set the verbose level of the ZED SDK + sdk_verbose_log_file: '' # Path to the file where the ZED SDK will log its messages. If empty, no file will be created. The log level can be set using the `sdk_verbose` parameter. + use_pub_timestamps: false # Use the current ROS time for the message timestamp instead of the camera timestamp. This is useful to test data communication latency. + debug_common: false + debug_dyn_params: false + debug_grab: false + debug_sim: false + debug_video_depth: false + debug_camera_controls: false + debug_point_cloud: false + debug_tf: false + debug_positional_tracking: false + debug_gnss: false + debug_sensors: false + debug_mapping: false + debug_terrain_mapping: false + debug_object_detection: false + debug_body_tracking: false + debug_roi: false + debug_streaming: false + debug_advanced: false + debug_nitros: false + disable_nitros: false # If available, disable NITROS usage for debugging and testing purposes diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/custom_object_detection.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/custom_object_detection.yaml new file mode 100644 index 0000000000..daacde19e5 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/custom_object_detection.yaml @@ -0,0 +1,1623 @@ +# Example of a custom object detection configuration file for the ZED ROS2 wrapper +# This file is used to configure the CUSTOM object detection parameters for the ZED camera. +# The parameters are defined in a YAML format and can be modified to suit the user's needs. +# The parameters are divided into sections for each CUSTOM object class, with each section containing +# specific parameters for that class. + +# This is an example of configuration file for a custom object detection model trained on the COCO dataset. +# COCO 2017 dataset https://cocodataset.org by Microsoft + +# To create a custom ONNX model, you can follow the online documentation: https://www.stereolabs.com/docs/yolo/export + +/**: + ros__parameters: + object_detection: + custom_onnx_file: '' # Path to the YOLO-like ONNX file for custom object detection directly performed by the ZED SDK + custom_onnx_input_size: 512 # Resolution used with the YOLO-like ONNX file. For example, 512 means a input tensor '1x3x512x512' + + custom_class_count: 80 # Number of classes in the custom ONNX file. For example, 80 for YOLOv8 trained on COCO dataset + + # TODO: Add one instance of each class to the list below + # Note: create a class_XXX identifier for each class in the custom ONNX file. + # Note: XXX is a number from 000 to 'custom_class_count-1', and it must be unique for each class. + # Note: the class_XXX identifier is not required to match the class ID [model_class_id] in the custom ONNX file. + + class_000: + label: 'person' + model_class_id: 0 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_001: + label: 'bicycle' + model_class_id: 1 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_002: + label: 'car' + model_class_id: 2 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_003: + label: 'motorcycle' + model_class_id: 3 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_004: + label: 'airplane' + model_class_id: 4 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_005: + label: 'bus' + model_class_id: 5 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_006: + label: 'train' + model_class_id: 6 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_007: + label: 'truck' + model_class_id: 7 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_008: + label: 'boat' + model_class_id: 8 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_009: + label: 'traffic light' + model_class_id: 9 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_010: + label: 'fire hydrant' + model_class_id: 10 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_011: + label: 'stop sign' + model_class_id: 11 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_012: + label: 'parking meter' + model_class_id: 12 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_013: + label: 'bench' + model_class_id: 13 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_014: + label: 'bird' + model_class_id: 14 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_015: + label: 'cat' + model_class_id: 15 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_016: + label: 'dog' + model_class_id: 16 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_017: + label: 'horse' + model_class_id: 17 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_018: + label: 'sheep' + model_class_id: 18 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_019: + label: 'cow' + model_class_id: 19 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_020: + label: 'elephant' + model_class_id: 20 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_021: + label: 'bear' + model_class_id: 21 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_022: + label: 'zebra' + model_class_id: 22 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_023: + label: 'giraffe' + model_class_id: 23 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_024: + label: 'backpack' + model_class_id: 24 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_025: + label: 'umbrella' + model_class_id: 25 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_026: + label: 'handbag' + model_class_id: 26 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_027: + label: 'tie' + model_class_id: 27 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_028: + label: 'suitcase' + model_class_id: 28 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_029: + label: 'frisbee' + model_class_id: 29 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_030: + label: 'skis' + model_class_id: 30 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_031: + label: 'snowboard' + model_class_id: 31 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_032: + label: 'sports ball' + model_class_id: 32 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_033: + label: 'kite' + model_class_id: 33 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_034: + label: 'baseball bat' + model_class_id: 34 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_035: + label: 'baseball glove' + model_class_id: 35 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_036: + label: 'skateboard' + model_class_id: 36 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_037: + label: 'surfboard' + model_class_id: 37 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_038: + label: 'tennis racket' + model_class_id: 38 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_039: + label: 'bottle' + model_class_id: 39 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_040: + label: 'wine glass' + model_class_id: 40 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_041: + label: 'cup' + model_class_id: 41 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_042: + label: 'fork' + model_class_id: 42 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_043: + label: 'knife' + model_class_id: 43 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_044: + label: 'spoon' + model_class_id: 44 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_045: + label: 'bowl' + model_class_id: 45 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_046: + label: 'banana' + model_class_id: 46 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_047: + label: 'apple' + model_class_id: 47 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_048: + label: 'sandwich' + model_class_id: 48 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_049: + label: 'orange' + model_class_id: 49 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_050: + label: 'broccoli' + model_class_id: 50 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_051: + label: 'carrot' + model_class_id: 51 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_052: + label: 'hot dog' + model_class_id: 52 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_053: + label: 'pizza' + model_class_id: 53 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_054: + label: 'donut' + model_class_id: 54 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_055: + label: 'cake' + model_class_id: 55 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_056: + label: 'chair' + model_class_id: 56 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_057: + label: 'couch' + model_class_id: 57 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_058: + label: 'potted plant' + model_class_id: 58 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_059: + label: 'bed' + model_class_id: 59 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_060: + label: 'dining table' + model_class_id: 60 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_061: + label: 'toilet' + model_class_id: 61 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_062: + label: 'tv' + model_class_id: 62 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_063: + label: 'laptop' + model_class_id: 63 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_064: + label: 'mouse' + model_class_id: 64 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_065: + label: 'remote' + model_class_id: 65 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_066: + label: 'keyboard' + model_class_id: 66 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_067: + label: 'cell phone' + model_class_id: 67 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_068: + label: 'microwave' + model_class_id: 68 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_069: + label: 'oven' + model_class_id: 69 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_070: + label: 'toaster' + model_class_id: 70 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_071: + label: 'sink' + model_class_id: 71 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_072: + label: 'refrigerator' + model_class_id: 72 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_073: + label: 'book' + model_class_id: 73 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_074: + label: 'clock' + model_class_id: 74 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_075: + label: 'vase' + model_class_id: 75 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_076: + label: 'scissors' + model_class_id: 76 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_077: + label: 'teddy bear' + model_class_id: 77 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_078: + label: 'hair drier' + model_class_id: 78 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + + class_079: + label: 'toothbrush' + model_class_id: 79 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/object_detection.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/object_detection.yaml new file mode 100644 index 0000000000..42a39a7e4d --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/object_detection.yaml @@ -0,0 +1,26 @@ +/**: + ros__parameters: + object_detection: + class: + people: + enabled: true # [DYNAMIC] - Enable/disable the detection of persons + confidence_threshold: 65.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + vehicle: + enabled: true # [DYNAMIC] - Enable/disable the detection of vehicles + confidence_threshold: 60.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + bag: + enabled: true # [DYNAMIC] - Enable/disable the detection of bags + confidence_threshold: 40.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + animal: + enabled: true # [DYNAMIC] - Enable/disable the detection of animals + confidence_threshold: 40.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + electronics: + enabled: true # [DYNAMIC] - Enable/disable the detection of electronic devices + confidence_threshold: 45.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + fruit_vegetable: + enabled: true # [DYNAMIC] - Enable/disable the detection of fruits and vegetables + confidence_threshold: 50.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + sport: + enabled: true # [DYNAMIC] - Enable/disable the detection of sport-related objects + confidence_threshold: 30.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/virtual.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/virtual.yaml new file mode 100644 index 0000000000..52ecec8b1a --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/virtual.yaml @@ -0,0 +1,27 @@ +# config/zedx.yaml +# Parameters for Stereolabs ZED X camera +--- +/**: + ros__parameters: + general: + camera_model: 'virtual' + camera_name: 'virtual' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. '4K', 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 1000.0 diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zed.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zed.yaml new file mode 100644 index 0000000000..a466dd24e9 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zed.yaml @@ -0,0 +1,19 @@ +# config/zed_yaml +# Parameters for Stereolabs ZED camera +--- +/**: + ros__parameters: + general: + camera_model: 'zed' + camera_name: 'zed' # overwritten by launch file + grab_resolution: 'HD720' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 20.0 diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zed2.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zed2.yaml new file mode 100644 index 0000000000..2d39fce487 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zed2.yaml @@ -0,0 +1,20 @@ +# config/zed2_yaml +# Parameters for Stereolabs ZED2 camera +--- +/**: + ros__parameters: + general: + camera_model: 'zed2' + camera_name: 'zed2' # overwritten by launch file + grab_resolution: 'HD720' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zed2i.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zed2i.yaml new file mode 100644 index 0000000000..9e27b0f00e --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zed2i.yaml @@ -0,0 +1,21 @@ +# config/zed2i_yaml +# Parameters for Stereolabs zed2i camera + +--- +/**: + ros__parameters: + general: + camera_model: 'zed2i' + camera_name: 'zed2i' # overwritten by launch file + grab_resolution: 'HD1080' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 15 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedm.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedm.yaml new file mode 100644 index 0000000000..66319a997b --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedm.yaml @@ -0,0 +1,20 @@ +# config/zedm_yaml +# Parameters for Stereolabs ZED mini camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedm' + camera_name: 'zedm' # overwritten by launch file + grab_resolution: 'HD1080' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 15.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedx.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedx.yaml new file mode 100644 index 0000000000..897b76af54 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedx.yaml @@ -0,0 +1,28 @@ +# config/zedx.yaml +# Parameters for Stereolabs ZED X camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedx' + camera_name: 'zedx' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 40.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdr.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdr.yaml new file mode 100644 index 0000000000..3cf417568c --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdr.yaml @@ -0,0 +1,28 @@ +# config/zedxhdr.yaml +# Parameters for Stereolabs ZED X HDR camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxhdr' + camera_name: 'zedxhdr' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 40.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmax.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmax.yaml new file mode 100644 index 0000000000..85df02e0e1 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmax.yaml @@ -0,0 +1,28 @@ +# config/zedxhdrmax.yaml +# Parameters for Stereolabs ZED X HDR MAX camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxhdrmax' + camera_name: 'zedxhdrmax' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 20.0 # Min: 0.5, Max: 40.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmini.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmini.yaml new file mode 100644 index 0000000000..39200c2d0c --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxhdrmini.yaml @@ -0,0 +1,28 @@ +# config/zedxhdrmini.yaml +# Parameters for Stereolabs ZED X HDR MINI camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxhdrmini' + camera_name: 'zedxhdrmini' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedxm.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxm.yaml new file mode 100644 index 0000000000..833b5dffae --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxm.yaml @@ -0,0 +1,28 @@ +# config/zedxm_yaml +# Parameters for Stereolabs ZED X Mini camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxm' + camera_name: 'zedxm' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + exposure_time: 16666 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 16666 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 8000 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 128 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedxone4k.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxone4k.yaml new file mode 100644 index 0000000000..a8efcaa887 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxone4k.yaml @@ -0,0 +1,14 @@ +# config/zedxone4k.yaml +# Parameters for Stereolabs ZED X One 4K camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxone4k' + camera_name: 'zedxone4k' # overwritten by launch file + grab_resolution: 'QHDPLUS' # The native camera grab resolution. 'HD4K', 'HD1200', 'QHDPLUS, 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD4K/QHDPLUS: 15 - HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + enable_hdr: false # When set to true, the camera will be set in HDR mode if the camera model and resolution allows it + diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedxonegs.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxonegs.yaml new file mode 100644 index 0000000000..f4d08b0026 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxonegs.yaml @@ -0,0 +1,10 @@ +# config/zedxonegs.yaml +# Parameters for Stereolabs ZED X One GS camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxonegs' + camera_name: 'zedxonegs' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/zed_debug/config/zedxonehdr.yaml b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxonehdr.yaml new file mode 100644 index 0000000000..e9f756744d --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/config/zedxonehdr.yaml @@ -0,0 +1,10 @@ +# config/zedxonehdr.yaml +# Parameters for Stereolabs ZED X One HDR camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxonehdr' + camera_name: 'zedxonehdr' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/zed_debug/launch/zed_camera_debug.launch.py b/src/lib/zed-ros2-wrapper/zed_debug/launch/zed_camera_debug.launch.py new file mode 100644 index 0000000000..c6d5e5c8d4 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/launch/zed_camera_debug.launch.py @@ -0,0 +1,436 @@ +# Copyright 2025 Stereolabs +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an 'AS IS' BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch.actions import ( + DeclareLaunchArgument, + OpaqueFunction, + LogInfo +) +from launch.conditions import IfCondition +from launch.substitutions import ( + LaunchConfiguration, + Command, + TextSubstitution +) +from launch_ros.actions import ( + Node +) + +# Enable colored output +os.environ["RCUTILS_COLORIZED_OUTPUT"] = "1" + +# ZED Configurations to be loaded by ZED Node +default_config_common = os.path.join( + get_package_share_directory('zed_debug'), + 'config', + 'common' +) + +# Object Detection Configuration to be loaded by ZED Node +default_object_detection_config_path = os.path.join( + get_package_share_directory('zed_debug'), + 'config', + 'object_detection.yaml' +) +# Custom Object Detection Configuration to be loaded by ZED Node +default_custom_object_detection_config_path = os.path.join( + get_package_share_directory('zed_debug'), + 'config', + 'custom_object_detection.yaml' +) + +# URDF/xacro file to be loaded by the Robot State Publisher node +default_xacro_path = os.path.join( + get_package_share_directory('zed_description'), + 'urdf', + 'zed_descr.urdf.xacro' +) + +# Function to parse array-like launch arguments +def parse_array_param(param): + cleaned = param.replace('[', '').replace(']', '').replace(' ', '') + if not cleaned: + return [] + return cleaned.split(',') + +def launch_setup(context, *args, **kwargs): + return_array = [] + + # Launch configuration variables + node_log_type = LaunchConfiguration('node_log_type') + + svo_path = LaunchConfiguration('svo_path') + publish_svo_clock = LaunchConfiguration('publish_svo_clock') + + use_sim_time = LaunchConfiguration('use_sim_time') + sim_mode = LaunchConfiguration('sim_mode') + sim_address = LaunchConfiguration('sim_address') + sim_port = LaunchConfiguration('sim_port') + + stream_address = LaunchConfiguration('stream_address') + stream_port = LaunchConfiguration('stream_port') + + namespace = LaunchConfiguration('namespace') + camera_name = LaunchConfiguration('camera_name') + camera_model = LaunchConfiguration('camera_model') + + node_name = LaunchConfiguration('node_name') + + ros_params_override_path = LaunchConfiguration('ros_params_override_path') + object_detection_config_path = LaunchConfiguration('object_detection_config_path') + custom_object_detection_config_path = LaunchConfiguration('custom_object_detection_config_path') + + serial_number = LaunchConfiguration('serial_number') + camera_id = LaunchConfiguration('camera_id') + + serial_numbers = LaunchConfiguration('serial_numbers') + camera_ids = LaunchConfiguration('camera_ids') + + publish_urdf = LaunchConfiguration('publish_urdf') + publish_tf = LaunchConfiguration('publish_tf') + publish_map_tf = LaunchConfiguration('publish_map_tf') + publish_imu_tf = LaunchConfiguration('publish_imu_tf') + xacro_path = LaunchConfiguration('xacro_path') + + enable_gnss = LaunchConfiguration('enable_gnss') + gnss_antenna_offset = LaunchConfiguration('gnss_antenna_offset') + + cmd_prefix = LaunchConfiguration('cmd_prefix') + + if( cmd_prefix.perform(context) == ''): + prefix_string = '' + else: + #prefix_string = 'xterm -geometry 250x40 -e ' + cmd_prefix.perform(context) + prefix_string = cmd_prefix.perform(context) + info = 'Using command prefix: `' + prefix_string + '`' + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + node_log_type_val = node_log_type.perform(context) + namespace_val = namespace.perform(context) + camera_name_val = camera_name.perform(context) + camera_model_val = camera_model.perform(context) + node_name_val = node_name.perform(context) + enable_gnss_val = enable_gnss.perform(context) + gnss_coords = parse_array_param(gnss_antenna_offset.perform(context)) + serial_numbers_val = serial_numbers.perform(context) + camera_ids_val = camera_ids.perform(context) + + if(node_log_type_val == 'both'): + node_log_effective = 'both' + else: # 'screen' or 'log' + node_log_effective = { + 'stdout': node_log_type_val, + 'stderr': node_log_type_val + } + + if (camera_name_val == ''): + camera_name_val = 'zed' + + if (camera_model_val == 'virtual'): + # Virtual Stereo Camera setup + serials = parse_array_param(serial_numbers_val) + ids = parse_array_param(camera_ids_val) + + # If not in live mode, at least one of serials or ids must be a valid 2-values array + if(len(serials) != 2 and len(ids) != 2 and svo_path.perform(context) == 'live'): + return [ + LogInfo(msg=TextSubstitution( + text='With a Virtual Stereo Camera setup, one of `serial_numbers` or `camera_ids` launch arguments must contain two valid values (Left and Right camera identification).')) + ] + + if(namespace_val == ''): + namespace_val = camera_name_val + '_debug' + else: + node_name_val = camera_name_val + '_debug' + + # Common configuration file + if (camera_model_val == 'zed' or + camera_model_val == 'zedm' or + camera_model_val == 'zed2' or + camera_model_val == 'zed2i' or + camera_model_val == 'zedx' or + camera_model_val == 'zedxm' or + camera_model_val == 'zedxhdr' or + camera_model_val == 'zedxhdrmini' or + camera_model_val == 'zedxhdrmax' or + camera_model_val == 'virtual'): + config_common_path_val = default_config_common + '_stereo.yaml' + else: + config_common_path_val = default_config_common + '_mono.yaml' + + info = 'Using common configuration file: ' + config_common_path_val + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # Camera configuration file + config_camera_path = os.path.join( + get_package_share_directory('zed_debug'), + 'config', + camera_model_val + '.yaml' + ) + + info = 'Using camera configuration file: ' + config_camera_path + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # Object Detection configuration file + info = 'Using Object Detection configuration file: ' + object_detection_config_path.perform(context) + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # Custom Object Detection configuration file + info = 'Using Custom Object Detection configuration file: ' + custom_object_detection_config_path.perform(context) + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # ROS parameters override file + ros_params_override_path_val = ros_params_override_path.perform(context) + if(ros_params_override_path_val != ''): + info = 'Using ROS parameters override file: ' + ros_params_override_path_val + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # Xacro command with options + xacro_command = [] + xacro_command.append('xacro') + xacro_command.append(' ') + xacro_command.append(xacro_path.perform(context)) + xacro_command.append(' ') + xacro_command.append('camera_name:=') + xacro_command.append(camera_name_val) + xacro_command.append(' ') + xacro_command.append('camera_model:=') + xacro_command.append(camera_model_val) + xacro_command.append(' ') + if(enable_gnss_val=='true'): + xacro_command.append(' ') + xacro_command.append('enable_gnss:=true') + xacro_command.append(' ') + if(len(gnss_coords)==3): + xacro_command.append('gnss_x:=') + xacro_command.append(gnss_coords[0]) + xacro_command.append(' ') + xacro_command.append('gnss_y:=') + xacro_command.append(gnss_coords[1]) + xacro_command.append(' ') + xacro_command.append('gnss_z:=') + xacro_command.append(gnss_coords[2]) + xacro_command.append(' ') + + # Robot State Publisher node + rsp_name = camera_name_val + '_state_publisher' + rsp_node = Node( + condition=IfCondition(publish_urdf), + package='robot_state_publisher', + namespace=namespace_val, + executable='robot_state_publisher', + name=rsp_name, + output=node_log_effective, + parameters=[{ + 'use_sim_time': publish_svo_clock, + 'robot_description': Command(xacro_command) + }], + remappings=[('robot_description', camera_name_val+'_description')] + ) + return_array.append(rsp_node) + + # ZED Node parameters + node_parameters = [] + + # Add YAML files + if(config_common_path_val != ''): + node_parameters.append(config_common_path_val) + if(config_camera_path != ''): + node_parameters.append(config_camera_path) + if(object_detection_config_path != ''): + node_parameters.append(object_detection_config_path.perform(context)) + if(custom_object_detection_config_path != ''): + node_parameters.append(custom_object_detection_config_path.perform(context)) + if( ros_params_override_path_val != ''): + node_parameters.append(ros_params_override_path.perform(context)) + + # Add launch arguments overrides + node_parameters.append( + # Launch arguments must override the YAML files values + { + 'use_sim_time': use_sim_time, + 'simulation.sim_enabled': sim_mode, + 'simulation.sim_address': sim_address, + 'simulation.sim_port': sim_port, + 'stream.stream_address': stream_address, + 'stream.stream_port': stream_port, + 'general.camera_name': camera_name_val, + 'general.camera_model': camera_model_val, + 'svo.svo_path': svo_path, + 'svo.publish_svo_clock': publish_svo_clock, + 'general.serial_number': serial_number, + 'general.camera_id': camera_id, + 'pos_tracking.publish_tf': publish_tf, + 'pos_tracking.publish_map_tf': publish_map_tf, + 'sensors.publish_imu_tf': publish_imu_tf, + 'gnss_fusion.gnss_fusion_enabled': enable_gnss, + 'general.virtual_serial_numbers': serial_numbers_val, + 'general.virtual_camera_ids': camera_ids_val + } + ) + + # Select what camera component to load in the Executor at Runtime + exe_args = [] + if( camera_model_val == 'zedxonegs' or + camera_model_val == 'zedxone4k' or + camera_model_val == 'zedxonehdr' ): + exe_args.append('--monocular') + + # ZED Wrapper node with hardcoded container + zed_node = Node( + executable='zed_debug_proc', + package='zed_debug', + name=node_name_val, + namespace=namespace_val, + parameters=node_parameters, + output='screen', + prefix=[prefix_string], + arguments=exe_args + ['--ros-args', '--log-level', 'debug'] + ) + return_array.append(zed_node) + + return return_array + +def generate_launch_description(): + return LaunchDescription( + [ + # Declare launch arguments + DeclareLaunchArgument( + 'node_log_type', + default_value=TextSubstitution(text='both'), + description='The log type of the node. It can be `screen`, `log` or `both`. The `log` type will save the log in a file in the `~/.ros/log/` folder. The `screen` type will print the log on the terminal. The `both` type will do both.', + choices=['screen', 'log', 'both']), + DeclareLaunchArgument( + 'camera_name', + default_value=TextSubstitution(text='zed'), + description='The name of the camera. It can be different from the camera model and it will be used as node `namespace`.'), + DeclareLaunchArgument( + 'camera_model', + description='[REQUIRED] The model of the camera. Using a wrong camera model can disable camera features.', + choices=['zed', 'zedm', 'zed2', 'zed2i', 'zedx', 'zedxm', 'zedxhdr', 'zedxhdrmini', 'zedxhdrmax', 'virtual', 'zedxonegs', 'zedxone4k', 'zedxonehdr']), + DeclareLaunchArgument( + 'namespace', + default_value='', + description='The namespace of the node. If empty (default) the camera name is used.'), + DeclareLaunchArgument( + 'node_name', + default_value='zed_debug_node', + description='The name of the zed_debug node. All the topic will have the same prefix: `///`. If a namespace is specified, the node name is replaced by the camera name.'), + DeclareLaunchArgument( + 'ros_params_override_path', + default_value='', + description='The path to an additional parameters file to override the default values.'), + DeclareLaunchArgument( + 'object_detection_config_path', + default_value=TextSubstitution(text=default_object_detection_config_path), + description='Path to the YAML configuration file for the Object Detection parameters.'), + DeclareLaunchArgument( + 'custom_object_detection_config_path', + default_value=TextSubstitution(text=default_custom_object_detection_config_path), + description='Path to the YAML configuration file for the Custom Object Detection parameters.'), + DeclareLaunchArgument( + 'serial_number', + default_value='0', + description='The serial number of the camera to be opened. It is mandatory to use this parameter or camera ID in multi-camera rigs to distinguish between different cameras. Use `ZED_Explorer -a` to retrieve the serial number of all the connected cameras.'), + DeclareLaunchArgument( + 'serial_numbers', + default_value='[]', + description='The serial numbers of the two cameras to be opened to compose a Virtual Stereo Camera, [left_sn,right_sn]. Use `ZED_Explorer -a` to retrieve the serial number of all the connected cameras.'), + DeclareLaunchArgument( + 'camera_id', + default_value='-1', + description='The ID of the camera to be opened. It is mandatory to use this parameter or serial number in multi-camera rigs to distinguish between different cameras. Use `ZED_Explorer -a` to retrieve the ID of all the connected cameras.'), + DeclareLaunchArgument( + 'camera_ids', + default_value='[]', + description='The IDs of the two cameras to be opened to compose a Virtual Stereo Camera, [left_id,right_id]. Use `ZED_Explorer -a` to retrieve the ID of all the connected cameras.'), + DeclareLaunchArgument( + 'publish_urdf', + default_value='true', + description='Enable URDF processing and starts Robot State Published to propagate static TF.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'publish_tf', + default_value='true', + description='Enable publication of the `odom -> camera_link` TF.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'publish_map_tf', + default_value='true', + description='Enable publication of the `map -> odom` TF. Note: Ignored if `publish_tf` is False.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'publish_imu_tf', + default_value='false', + description='Enable publication of the IMU TF. Note: Ignored if `publish_tf` is False.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'xacro_path', + default_value=TextSubstitution(text=default_xacro_path), + description='Path to the camera URDF file as a xacro file.'), + DeclareLaunchArgument( + 'svo_path', + default_value=TextSubstitution(text='live'), + description='Path to an input SVO file.'), + DeclareLaunchArgument( + 'publish_svo_clock', + default_value='false', + description='If set to `true` the node will act as a clock server publishing the SVO timestamp. This is useful for node synchronization'), + DeclareLaunchArgument( + 'enable_gnss', + default_value='false', + description='Enable GNSS fusion to fix positional tracking pose with GNSS data from messages of type `sensor_msgs::msg::NavSatFix`. The fix topic can be customized in `common_stereo.yaml`.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'gnss_antenna_offset', + default_value='[]', + description='Position of the GNSS antenna with respect to the mounting point of the ZED camera. Format: [x,y,z]'), + DeclareLaunchArgument( + 'use_sim_time', + default_value='false', + description='If set to `true` the node will wait for messages on the `/clock` topic to start and will use this information as the timestamp reference', + choices=['true', 'false']), + DeclareLaunchArgument( + 'sim_mode', + default_value='false', + description='Enable simulation mode. Set `sim_address` and `sim_port` to configure the simulator input.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'sim_address', + default_value='127.0.0.1', + description='The connection address of the simulation server. See the documentation of the supported simulation plugins for more information.'), + DeclareLaunchArgument( + 'sim_port', + default_value='30000', + description='The connection port of the simulation server. See the documentation of the supported simulation plugins for more information.'), + DeclareLaunchArgument( + 'stream_address', + default_value='', + description='The connection address of the input streaming server.'), + DeclareLaunchArgument( + 'stream_port', + default_value='30000', + description='The connection port of the input streaming server.'), + DeclareLaunchArgument( + 'cmd_prefix', + default_value='', + description='A prefix to be added to the node executable, to run debugging tools like `valgrind` or `gdb`. For example: `valgrind --leak-check=full` or `gdb --args`.'), + OpaqueFunction(function=launch_setup) + ] + ) diff --git a/src/lib/zed-ros2-wrapper/zed_debug/package.xml b/src/lib/zed-ros2-wrapper/zed_debug/package.xml new file mode 100644 index 0000000000..333b5cfdb7 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/package.xml @@ -0,0 +1,34 @@ + + + + zed_debug + 5.2.2 + Package to debug ZED Components by loading them in a single C++ process + STEREOLABS + Apache License 2.0 + https://www.stereolabs.com/ + https://github.com/stereolabs/zed-ros2-wrapper + https://github.com/stereolabs/zed-ros2-wrapper/issues + + ament_cmake + + ament_cmake_auto + + rclcpp + rclcpp_components + rcutils + zed_components + backward_ros + + ament_lint_auto + ament_cmake_copyright + ament_cmake_cppcheck + ament_cmake_lint_cmake + ament_cmake_pep257 + ament_cmake_uncrustify + ament_cmake_xmllint + + + ament_cmake + + \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/zed_debug/src/zed_debug_proc.cpp b/src/lib/zed-ros2-wrapper/zed_debug/src/zed_debug_proc.cpp new file mode 100644 index 0000000000..38b660ee5e --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_debug/src/zed_debug_proc.cpp @@ -0,0 +1,64 @@ +// Copyright 2026 Stereolabs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +int main(int argc, char ** argv) +{ + // Disable stdout buffering for better logging visibility + setvbuf(stdout, NULL, _IONBF, BUFSIZ); + + // Initialize ROS 2 + rclcpp::init(argc, argv); + + // Disable intra-process communication + rclcpp::NodeOptions options; + options.use_intra_process_comms(false); + + // Check for monocular mode argument + bool monocular_mode = false; + for (int i = 1; i < argc; ++i) { + std::string mode_arg = argv[i]; + if (mode_arg == "--monocular") { + monocular_mode = true; + break; + } + } + + // Create the appropriate ZED camera node (monocular or stereo) + rclcpp::Node::SharedPtr zed_component; + if (monocular_mode) { + RCLCPP_INFO( + rclcpp::get_logger("zed_debug_proc"), + "Debugging ZED Camera One (monocular) node..."); + zed_component = std::make_shared(options); + } else { + RCLCPP_INFO( + rclcpp::get_logger("zed_debug_proc"), + "Debugging ZED Camera (stereo) node..."); + zed_component = std::make_shared(options); + } + + // Create single-threaded executor and spin the node + rclcpp::executors::SingleThreadedExecutor executor; + executor.add_node(zed_component); + executor.spin(); + + // Shutdown ROS 2 + rclcpp::shutdown(); + + return EXIT_SUCCESS; +} diff --git a/src/lib/zed-ros2-wrapper/zed_ros2/CMakeLists.txt b/src/lib/zed-ros2-wrapper/zed_ros2/CMakeLists.txt new file mode 100644 index 0000000000..28b6ca7f38 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_ros2/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 3.8) +project(zed_ros2 NONE) + +## Generate symbols for IDE indexer +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +################################################ +# Check the ROS2 version + +set(ROS2_FOUND FALSE) +if(DEFINED ENV{ROS_DISTRO}) + set(FOUND_ROS2_DISTRO $ENV{ROS_DISTRO}) + set(ROS2_FOUND TRUE) + #message("* Found ROS2 ${FOUND_ROS2_DISTRO}") +else() + message("* ROS2 distro variable not set. Trying to figure it out...") + set(ROS2_DISTROS "ardent;bouncy;crystal;dashing;eloquent;foxy;galactic;humble;iron;jazzy;kilted;rolling") + set(ROS2_FOUND FALSE) + foreach(distro ${ROS2_DISTROS}) + if(NOT ROS2_FOUND) + find_path(RCLCPP_H rclcpp.hpp PATHS /opt/ros/${distro}/include/rclcpp) + if(RCLCPP_H) + #message("* Found ROS2 ${distro}") + set(FOUND_ROS2_DISTRO ${distro}) + set(ROS2_FOUND TRUE) + endif() + endif() + endforeach() +endif() + +if(ROS2_FOUND) + if(${FOUND_ROS2_DISTRO} STREQUAL "foxy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_FOXY) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "humble") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_HUMBLE) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "iron") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_IRON) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "jazzy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_JAZZY) + else() + message("*** WARNING *** Unsupported ROS2 ${FOUND_ROS2_DISTRO}. '${PROJECT_NAME}' may not work correctly.") + endif() +else() + message("*** WARNING *** ROS2 distro is unknown. This package could not work correctly.") +endif() +################################################ + +find_package(ament_cmake_auto REQUIRED) +ament_auto_find_build_dependencies() + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + ament_lint_auto_find_test_dependencies() +endif() + +############################################################################### +# Add all files in subdirectories of the project in +# a dummy_target so qtcreator have access to all files +file(GLOB_RECURSE all_files ${CMAKE_CURRENT_SOURCE_DIR}/*) +add_custom_target(all_${PROJECT_NAME}_files SOURCES ${all_files}) +############################################################################### + +ament_package() diff --git a/src/lib/zed-ros2-wrapper/zed_ros2/package.xml b/src/lib/zed-ros2-wrapper/zed_ros2/package.xml new file mode 100644 index 0000000000..04751ae6a6 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_ros2/package.xml @@ -0,0 +1,33 @@ + + + + zed_ros2 + 5.2.2 + Stereolabs zed-ros2-wrapper support meta package + STEREOLABS + Apache License 2.0 + http://stereolabs.com/ + https://github.com/stereolabs/zed-ros2-wrapper + https://github.com/stereolabs/zed-ros2-wrapper/issues + + ament_cmake + + ament_cmake_auto + + zed_msgs + zed_description + zed_components + zed_wrapper + + ament_lint_auto + ament_cmake_copyright + ament_cmake_cppcheck + ament_cmake_lint_cmake + ament_cmake_pep257 + ament_cmake_uncrustify + ament_cmake_xmllint + + + ament_cmake + + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/CMakeLists.txt b/src/lib/zed-ros2-wrapper/zed_wrapper/CMakeLists.txt new file mode 100644 index 0000000000..6407536d61 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 3.8) +project(zed_wrapper) + +## Generate symbols for IDE indexer +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +################################################ +# Check the ROS2 version + +set(ROS2_FOUND FALSE) +if(DEFINED ENV{ROS_DISTRO}) + set(FOUND_ROS2_DISTRO $ENV{ROS_DISTRO}) + set(ROS2_FOUND TRUE) + #message("* Found ROS2 ${FOUND_ROS2_DISTRO}") +else() + message("* ROS2 distro variable not set. Trying to figure it out...") + set(ROS2_DISTROS "ardent;bouncy;crystal;dashing;eloquent;foxy;galactic;humble;iron;jazzy;kilted;rolling") + set(ROS2_FOUND FALSE) + foreach(distro ${ROS2_DISTROS}) + if(NOT ROS2_FOUND) + find_path(RCLCPP_H rclcpp.hpp PATHS /opt/ros/${distro}/include/rclcpp) + if(RCLCPP_H) + #message("* Found ROS2 ${distro}") + set(FOUND_ROS2_DISTRO ${distro}) + set(ROS2_FOUND TRUE) + endif() + endif() + endforeach() +endif() + +if(ROS2_FOUND) + if(${FOUND_ROS2_DISTRO} STREQUAL "foxy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_FOXY) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "iron") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_IRON) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "humble") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_HUMBLE) + elseif(${FOUND_ROS2_DISTRO} STREQUAL "jazzy") + #message("* ROS2 ${FOUND_ROS2_DISTRO} is officially supported by this package.") + add_definitions(-DFOUND_JAZZY) + else() + message("*** WARNING *** Unsupported ROS2 ${FOUND_ROS2_DISTRO}. '${PROJECT_NAME}' may not work correctly.") + endif() +else() + message("*** WARNING *** ROS2 distro is unknown. This package could not work correctly.") +endif() +################################################ + +############################################# +# Dependencies +find_package(ament_cmake_auto REQUIRED) +ament_auto_find_build_dependencies() + +############################################# +# Install + +# Install PARAMS files +install(DIRECTORY + config + DESTINATION share/${PROJECT_NAME} +) + +# Install URDF files +install(DIRECTORY + urdf + DESTINATION share/${PROJECT_NAME} +) + +# Install LAUNCH files +install(DIRECTORY + launch + DESTINATION share/${PROJECT_NAME} +) + +ament_package() diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/common_mono.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/common_mono.yaml new file mode 100644 index 0000000000..fd905f9ea0 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/common_mono.yaml @@ -0,0 +1,84 @@ +# config/common_mono.yaml +# Common parameters to Stereolabs ZED Stereo cameras + +--- +/**: + ros__parameters: + general: + serial_number: 0 # overwritten by launch file + pub_resolution: "CUSTOM" # The resolution used for output. 'NATIVE' to use the same `general.grab_resolution` - `CUSTOM` to apply the `general.pub_downscale_factor` downscale factory to reduce bandwidth in transmission + pub_downscale_factor: 2.0 # rescale factor used to rescale image before publishing when 'pub_resolution' is 'CUSTOM' + gpu_id: -1 + optional_opencv_calibration_file: "" # Optional path where the ZED SDK can find a file containing the calibration information of the camera computed by OpenCV. Read the ZED SDK documentation for more information: https://www.stereolabs.com/docs/api/structsl_1_1InitParameters.html#a9eab2753374ef3baec1d31960859ba19 + publish_status: true # Enable/Disable the publishing of the camera status topic + + svo: + decryption_key: "" # Optional decryption key/passphrase when opening encrypted SVO files + use_svo_timestamps: true # Use the SVO timestamps to publish data. If false, data will be published at the system time. + publish_svo_clock: true # [overwritten by launch file options] When use_svo_timestamps is true allows to publish the SVO clock to the `/clock` topic. This is useful for synchronous rosbag playback. + svo_loop: false # Enable loop mode when using an SVO as input source. NOTE: ignored if SVO timestamping is used + svo_realtime: true # if true the SVO will be played trying to respect the original framerate eventually skipping frames, otherwise every frame will be processed respecting the `pub_frame_rate` setting + play_from_frame: 0 # Start playing the SVO from a specific frame + + video: + saturation: 4 # [DYNAMIC] + sharpness: 4 # [DYNAMIC] + gamma: 8 # [DYNAMIC] + auto_whitebalance: true # [DYNAMIC] + whitebalance_temperature: 42 # [DYNAMIC] - [28,65] x100 - works only if `auto_whitebalance` is false + auto_exposure: true # [DYNAMIC] - Enables or disables auto exposure control. false: manual, true: auto + exposure_time: 16000 # [DYNAMIC] - Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # [DYNAMIC] - Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # [DYNAMIC] - Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # [DYNAMIC] - Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + auto_analog_gain: true # [DYNAMIC] - Enables or disables auto gain control. false: manual, true: auto + analog_gain: 1255 # [DYNAMIC] - Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # [DYNAMIC] - Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # [DYNAMIC] - Defines the maximum range of sensor gain in automatic control + auto_digital_gain: false # [DYNAMIC] - Enables or disables auto digital gain control. false: manual, true: auto + digital_gain: 1 # [DYNAMIC] - Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # [DYNAMIC] - Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # [DYNAMIC] - Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # [DYNAMIC] - Defines the level of denoising applied on both left and right images. Range [0-100] + enable_24bit_output: false # [SDK >= 5.1] Enable BGR 24-bit output for lower bandwidth usage. If false, BGRA 32-bit output is used (old way before SDK v5.1) + publish_rgb: true # Advertise the RGB image topics that are published only if a node subscribes to them + publish_gray: false # Advertise the gray image topics that are published only if a node subscribes to them + publish_raw: false # Advertise the raw image topics that are published only if a node subscribes to them (only if 'publish_rgb' or 'publish_gray' is true) + + sensors: + publish_imu_tf: true # [overwritten by launch file options] enable/disable the IMU TF broadcasting + sensors_pub_rate: 100. # [DYNAMIC] - frequency of publishing of sensors data. MAX: 400. - MIN: grab rate + publish_imu: true # Advertise the IMU topic that is published only if a node subscribes to it + publish_imu_raw: false # Advertise the raw IMU topic that is published only if a node subscribes to it + publish_cam_imu_transf: false # Advertise the CAMERA-IMU transformation topic that is published only if a node subscribes to it + publish_temp: false # Advertise the temperature topics that are published only if a node subscribes to them + + stream_server: + stream_enabled: false # enable the streaming server when the camera is open + codec: 'H265' # different encoding types for image streaming: 'H264', 'H265' + port: 30000 # Port used for streaming. Port must be an even number. Any odd number will be rejected. + bitrate: 12500 # [1000 - 60000] Streaming bitrate (in Kbits/s) used for streaming. See https://www.stereolabs.com/docs/api/structsl_1_1StreamingParameters.html#a873ba9440e3e9786eb1476a3bfa536d0 + gop_size: -1 # [max 256] The GOP size determines the maximum distance between IDR/I-frames. Very high GOP size will result in slightly more efficient compression, especially on static scenes. But latency will increase. + adaptative_bitrate: false # Bitrate will be adjusted depending the number of packet dropped during streaming. If activated, the bitrate can vary between [bitrate/4, bitrate]. + chunk_size: 16084 # [1024 - 65000] Stream buffers are divided into X number of chunks where each chunk is chunk_size bytes long. You can lower chunk_size value if network generates a lot of packet lost: this will generates more chunk for a single image, but each chunk sent will be lighter to avoid inside-chunk corruption. Increasing this value can decrease latency. + target_framerate: 0 # Framerate for the streaming output. This framerate must be below or equal to the camera framerate. Allowed framerates are 15, 30, 60 or 100 if possible. Any other values will be discarded and camera FPS will be taken. + + advanced: # WARNING: do not modify unless you are confident of what you are doing + # Reference documentation: https://man7.org/linux/man-pages/man7/sched.7.html + thread_sched_policy: "SCHED_BATCH" # 'SCHED_OTHER', 'SCHED_BATCH', 'SCHED_FIFO', 'SCHED_RR' - NOTE: 'SCHED_FIFO' and 'SCHED_RR' require 'sudo' + thread_grab_priority: 50 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + thread_sensor_priority: 70 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + + debug: + sdk_verbose: 1 # Set the verbose level of the ZED SDK + sdk_verbose_log_file: '' # Path to the file where the ZED SDK will log its messages. If empty, no file will be created. The log level can be set using the `sdk_verbose` parameter. + use_pub_timestamps: false # Use the current ROS time for the message timestamp instead of the camera timestamp. This is useful to test data communication latency. + debug_common: false # Enable/Disable the printing of debug messages related to the common parameters and functionalities + debug_dyn_params: false # Enable/Disable the printing of debug messages related to dynamic parameters updates + debug_video_depth: false # Enable/Disable the printing of debug messages related to video and depth parameters and functionalities + debug_camera_controls: false # Enable/Disable the printing of debug messages related to camera controls (exposure, gain, white balance, etc) + debug_sensors: false # Enable/Disable the printing of debug messages related to sensors data and functionalities + debug_streaming: false # Enable/Disable the printing of debug messages related to the network streaming functionalities + debug_advanced: false # Enable/Disable the printing of debug messages related to advanced thread parameters and functionalities + debug_nitros: false # Enable/Disable the printing of debug messages related to NITROS functionalities + disable_nitros: false # If available, disable NITROS usage for debugging and testing purposes diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/common_stereo.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/common_stereo.yaml new file mode 100644 index 0000000000..151dcfc3c6 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/common_stereo.yaml @@ -0,0 +1,220 @@ +# config/common_stereo.yaml +# Common parameters to Stereolabs ZED Stereo cameras + +--- +/**: + ros__parameters: + use_sim_time: false # Set to `true` only if there is a publisher for the simulated clock to the `/clock` topic. Normally used in simulation mode. + + simulation: + sim_enabled: false # Set to `true` to enable the simulation mode and connect to a simulation server + sim_address: '127.0.0.1' # The connection address of the simulation server. See the documentation of the supported simulation plugins for more information. + sim_port: 30000 # The connection port of the simulation server. See the documentation of the supported simulation plugins for more information. + + svo: + decryption_key: "" # Optional decryption key/passphrase when opening encrypted SVO files + use_svo_timestamps: true # Use the SVO timestamps to publish data. If false, data will be published at the system time. + publish_svo_clock: false # [overwritten by launch file options] When use_svo_timestamps is true allows to publish the SVO clock to the `/clock` topic. This is useful for synchronous rosbag playback. + svo_loop: false # Enable loop mode when using an SVO as input source. NOTE: ignored if SVO timestamping is used + svo_realtime: false # if true the SVO will be played trying to respect the original framerate eventually skipping frames, otherwise every frame will be processed respecting the `pub_frame_rate` setting + play_from_frame: 0 # Start playing the SVO from a specific frame + replay_rate: 1.0 # Replay rate for the SVO when not used in realtime mode (between [0.10-5.0]) + + general: + camera_timeout_sec: 5 + camera_max_reconnect: 5 + camera_flip: false + self_calib: true # Enable the self-calibration process at camera opening. See https://www.stereolabs.com/docs/api/structsl_1_1InitParameters.html#affeaa06cfc1d849e311e484ceb8edcc5 + serial_number: 0 # overwritten by launch file + pub_resolution: 'CUSTOM' # The resolution used for image and depth map publishing. 'NATIVE' to use the same `general.grab_resolution` - `CUSTOM` to apply the `general.pub_downscale_factor` downscale factory to reduce bandwidth in transmission + pub_downscale_factor: 2.0 # rescale factor used to rescale image before publishing when 'pub_resolution' is 'CUSTOM' + grab_compute_capping_fps: 0.0 # Define a computation upper limit to the grab frequency. This can be useful to get a known constant fixed rate or limit the computation load while keeping a short exposure time by setting a high camera capture framerate. If set to 0, the grab compute capping will be disabled and the ZED SDK will process data at the grab rate. + pub_frame_rate: 0.0 # [DYNAMIC] Frequency of publishing of visual images and depth data (not the Point Cloud, see 'depth.point_cloud_freq'). This value must be <= the camera framerate. Set to 0 for no limit (= grab_frame_rate). + enable_image_validity_check: 1 # [SDK5 required] Sets the image validity check. If set to 1, the SDK will check if the frames are valid before processing. + gpu_id: -1 + optional_opencv_calibration_file: '' # Optional path where the ZED SDK can find a file containing the calibration information of the camera computed by OpenCV. Read the ZED SDK documentation for more information: https://www.stereolabs.com/docs/api/structsl_1_1InitParameters.html#a9eab2753374ef3baec1d31960859ba19 + async_image_retrieval: false # If set to true will camera image retrieve at a framerate different from \ref grab() application framerate. This is useful for recording SVO or sending camera stream at different rate than application. + publish_status: true # Advertise the status topics that are published only if a node subscribes to them + # Other parameters are defined, according to the camera model, in the 'zed.yaml', 'zedm.yaml', 'zed2.yaml', 'zed2i.yaml' + # 'zedx.yaml', 'zedxmini.yaml', 'virtual.yaml' files + + video: + saturation: 4 # [DYNAMIC] + sharpness: 4 # [DYNAMIC] + gamma: 8 # [DYNAMIC] + auto_exposure_gain: true # [DYNAMIC] + exposure: 80 # [DYNAMIC] + gain: 80 # [DYNAMIC] + auto_whitebalance: true # [DYNAMIC] + whitebalance_temperature: 42 # [DYNAMIC] - [28,65] x100 - works only if `auto_whitebalance` is false + enable_24bit_output: false # [SDK >= 5.1] Enable BGR 24-bit output for lower bandwidth usage. If false, BGRA 32-bit output is used (old way before SDK v5.1) + publish_rgb: true # Advertise the RGB image topics that are published only if a node subscribes to them + publish_left_right: false # Advertise the left and right image topics that are published only if a node subscribes to them + publish_raw: false # Advertise the raw image topics that are published only if a node subscribes to them + publish_gray: false # Advertise the gray image topics that are published only if a node subscribes to them + publish_stereo: false # Advertise the stereo image topic that is published only if a node subscribes to it + # Other parameters are defined, according to the camera model, in the 'zed.yaml', 'zedm.yaml', 'zed2.yaml', 'zed2i.yaml' + # 'zedx.yaml', 'zedxmini.yaml', 'virtual.yaml' files + + sensors: + publish_imu_tf: true # [overwritten by launch file options] enable/disable the IMU TF broadcasting + sensors_image_sync: false # Synchronize Sensors messages with latest published video/depth message + sensors_pub_rate: 100. # frequency of publishing of sensors data. MAX: 400. - MIN: grab rate + publish_imu: true # Advertise the IMU topic that is published only if a node subscribes to it + publish_imu_raw: false # Advertise the raw IMU topic that is published only if a node subscribes to it + publish_cam_imu_transf: false # Advertise the CAMERA-IMU transformation topic that is published only if a node subscribes to it + publish_mag: false # Advertise the magnetometer topic that is published only if a node subscribes to it + publish_baro: false # Advertise the barometer topic that is published only if a node subscribes to it + publish_temp: false # Advertise the temperature topics that are published only if a node subscribes to them + + region_of_interest: + automatic_roi: false # Enable the automatic ROI generation to automatically detect part of the robot in the FoV and remove them from the processing. Note: if enabled the value of `manual_polygon` is ignored + depth_far_threshold_meters: 2.5 # Filtering how far object in the ROI should be considered, this is useful for a vehicle for instance + image_height_ratio_cutoff: 0.5 # By default consider only the lower half of the image, can be useful to filter out the sky + #manual_polygon: '[]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + #manual_polygon: '[[0.25,0.33],[0.75,0.33],[0.75,0.5],[0.5,0.75],[0.25,0.5]]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + #manual_polygon: '[[0.25,0.25],[0.75,0.25],[0.75,0.75],[0.25,0.75]]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + #manual_polygon: '[[0.5,0.25],[0.75,0.5],[0.5,0.75],[0.25,0.5]]' # A polygon defining the ROI where the ZED SDK perform the processing ignoring the rest. Coordinates must be normalized to '1.0' to be resolution independent. + apply_to_depth: true # Apply ROI to depth processing + apply_to_positional_tracking: true # Apply ROI to positional tracking processing + apply_to_object_detection: true # Apply ROI to object detection processing + apply_to_body_tracking: true # Apply ROI to body tracking processing + apply_to_spatial_mapping: true # Apply ROI to spatial mapping processing + publish_roi_mask: false # Advertise the ROI mask image topic that is published only if a node subscribes to it + + depth: + depth_mode: 'NEURAL_LIGHT' # Matches the ZED SDK setting: 'NONE', 'NEURAL_LIGHT', 'NEURAL', 'NEURAL_PLUS' - Note: if 'NONE' all the modules that requires depth extraction are disabled by default (Pos. Tracking, Obj. Detection, Mapping, ...) + depth_stabilization: -1 # Negative value takes SDK default, 0 is disabled - Range: [0,100] + openni_depth_mode: false # 'false': 32bit float [meters], 'true': 16bit unsigned int [millimeters] + point_cloud_freq: 10.0 # [DYNAMIC] Frequency of the pointcloud publishing. This value must be <= the camera framerate. Set to 0 for no limit (= grab_frame_rate). + point_cloud_res: 'COMPACT' # The resolution used for point cloud publishing - 'COMPACT'-Standard resolution. Optimizes processing and bandwidth, 'REDUCED'-Half resolution. Low processing and bandwidth requirements + depth_confidence: 95 # [DYNAMIC] + depth_texture_conf: 100 # [DYNAMIC] + remove_saturated_areas: true # [DYNAMIC] + publish_depth_map: true # Advertise the depth map topics that are published only if a node subscribes to them + publish_depth_info: false # Advertise the depth info topic that is published only if a node subscribes to it + publish_point_cloud: true # Advertise the point cloud topic that is published only if a node subscribes to it + publish_depth_confidence: false # Advertise the depth confidence topic that is published only if a node subscribes to it + publish_disparity: false # Advertise the disparity topic that is published only if a node subscribes to it + # Other parameters are defined, according to the camera model, in the 'zed.yaml', 'zedm.yaml', 'zed2.yaml', 'zed2i.yaml' + # 'zedx.yaml', 'zedxmini.yaml', 'virtual.yaml' files + + pos_tracking: + pos_tracking_enabled: true # True to enable positional tracking from start + pos_tracking_mode: 'AUTO' # 'AUTO' uses the SDK default; also supports 'GEN_1', 'GEN_3' + imu_fusion: true # enable/disable IMU fusion. When set to false, only the optical odometry will be used. + publish_tf: true # [overwritten by launch file options] publish `odom -> camera_link` TF + publish_map_tf: true # [overwritten by launch file options] publish `map -> odom` TF + map_frame: 'map' + odometry_frame: 'odom' + area_memory: true # Enable to detect loop closure + area_file_path: '' # Path to the area memory file for relocalization and loop closure in a previously explored environment. + enable_localization_only: false # If true, the camera will only localize in the loaded area memory without updating the map with new information. + save_area_memory_on_closing: false # Save Area memory before closing the camera if `area_file_path` is not empty. You can also use the `save_area_memory` service to save the area memory at any time. + reset_odom_with_loop_closure: true # Re-initialize odometry to the last valid pose when loop closure happens (reset camera odometry drift) + publish_3d_landmarks: false # Publish 3D landmarks used by the positional tracking algorithm + publish_lm_skip_frame: 5 # Publish the landmarks every X frames to reduce bandwidth. Set to 0 to publish all landmarks + depth_min_range: 0.0 # Set this value for removing fixed zones of the robot in the FoV of the camerafrom the visual odometry evaluation + set_as_static: false # If 'true' the camera will be static and not move in the environment + set_gravity_as_origin: true # If 'true' align the positional tracking world to imu gravity measurement. Keep the yaw from the user initial pose. + floor_alignment: false # Enable to automatically calculate camera/floor offset + initial_base_pose: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # Initial position of the `camera_link` frame in the map -> [X, Y, Z, R, P, Y] + path_pub_rate: 2.0 # [DYNAMIC] - Camera trajectory publishing frequency. Set to 0 for no limit (= grab_frame_rate). + path_max_count: -1 # use '-1' for unlimited path size + two_d_mode: false # Force navigation on a plane. If true the Z value will be fixed to 'fixed_z_value', roll and pitch to zero + fixed_z_value: 0.0 # Value to be used for Z coordinate if `two_d_mode` is true + transform_time_offset: 0.0 # The value added to the timestamp of `map->odom` and `odom->camera_link` transform being generated + reset_pose_with_svo_loop: true # Reset the camera pose the `initial_base_pose` when the SVO loop is enabled and the SVO playback reaches the end of the file. + publish_odom_pose: true # Advertise the odometry and pose topics that are published only if a node subscribes to them + publish_pose_cov: false # Advertise the pose with covariance topic that is published only if a node subscribes to it + publish_cam_path: false # Advertise the camera odometry and pose path topics that are published only if a node subscribes to them + + gnss_fusion: + gnss_fusion_enabled: false # fuse 'sensor_msg/NavSatFix' message information into pose data + gnss_fix_topic: '/fix' # Name of the GNSS topic of type NavSatFix to subscribe [Default: '/gps/fix'] + gnss_zero_altitude: false # Set to `true` to ignore GNSS altitude information + h_covariance_mul: 1.0 # Multiplier factor to be applied to horizontal covariance of the received fix (plane X/Y) + v_covariance_mul: 1.0 # Multiplier factor to be applied to vertical covariance of the received fix (Z axis) + publish_utm_tf: true # Publish `utm` -> `map` TF + broadcast_utm_transform_as_parent_frame: false # if 'true' publish `utm` -> `map` TF, otherwise `map` -> `utm` + enable_reinitialization: false # determines whether reinitialization should be performed between GNSS and VIO fusion when a significant disparity is detected between GNSS data and the current fusion data. It becomes particularly crucial during prolonged GNSS signal loss scenarios. + enable_rolling_calibration: true # If this parameter is set to true, the fusion algorithm will used a rough VIO / GNSS calibration at first and then refine it. This allow you to quickly get a fused position. + enable_translation_uncertainty_target: false # When this parameter is enabled (set to true), the calibration process between GNSS and VIO accounts for the uncertainty in the determined translation, thereby facilitating the calibration termination. The maximum allowable uncertainty is controlled by the 'target_translation_uncertainty' parameter. + gnss_vio_reinit_threshold: 5.0 # determines the threshold for GNSS/VIO reinitialization. If the fused position deviates beyond out of the region defined by the product of the GNSS covariance and the gnss_vio_reinit_threshold, a reinitialization will be triggered. + target_translation_uncertainty: 0.1 # defines the target translation uncertainty at which the calibration process between GNSS and VIO concludes. By default, the threshold is set at 10 centimeters. + target_yaw_uncertainty: 0.1 # defines the target yaw uncertainty at which the calibration process between GNSS and VIO concludes. The unit of this parameter is in radian. By default, the threshold is set at 0.1 radians. + + mapping: + mapping_enabled: false # True to enable mapping t # Pand fused point cloud pubblication + resolution: 0.05 # maps resolution in meters [min: 0.01f - max: 0.2f] + max_mapping_range: 5.0 # maximum depth range while mapping in meters (-1 for automatic calculation) [2.0, 20.0] + fused_pointcloud_freq: 1.0 # frequency of the publishing of the fused colored point cloud. Set to 0 for no limit (= point_cloud_freq). + clicked_point_topic: '/clicked_point' # Topic published by Rviz when a point of the cloud is clicked. Used for plane detection + pd_max_distance_threshold: 0.15 # Plane detection: controls the spread of plane by checking the position difference. + pd_normal_similarity_threshold: 15.0 # Plane detection: controls the spread of plane by checking the angle difference. + publish_det_plane: false # Advertise the plane detection topics that is published only if a node subscribes to it + + object_detection: + od_enabled: false # True to enable Object Detection + enable_tracking: true # Whether the object detection system includes object tracking capabilities across a sequence of images. + detection_model: 'MULTI_CLASS_BOX_FAST' # 'MULTI_CLASS_BOX_FAST', 'MULTI_CLASS_BOX_MEDIUM', 'MULTI_CLASS_BOX_ACCURATE', 'PERSON_HEAD_BOX_FAST', 'PERSON_HEAD_BOX_ACCURATE', 'CUSTOM_YOLOLIKE_BOX_OBJECTS' + max_range: 40.0 # [m] Upper depth range for detections.The value cannot be greater than 'depth.max_depth' + filtering_mode: 'NMS3D' # Filtering mode that should be applied to raw detections: 'NONE', 'NMS3D', 'NMS3D_PER_CLASS' + prediction_timeout: 2.0 # During this time [sec], the object will have OK state even if it is not detected. Set this parameter to 0 to disable SDK predictions + allow_reduced_precision_inference: false # Allow inference to run at a lower precision to improve runtime and memory usage + # Other parameters are defined in the 'object_detection.yaml' and 'custom_object_detection.yaml' files + + body_tracking: + bt_enabled: false # True to enable Body Tracking + model: 'HUMAN_BODY_MEDIUM' # 'HUMAN_BODY_FAST', 'HUMAN_BODY_MEDIUM', 'HUMAN_BODY_ACCURATE' + body_format: 'BODY_38' # 'BODY_18','BODY_34','BODY_38' + allow_reduced_precision_inference: false # Allow inference to run at a lower precision to improve runtime and memory usage + max_range: 15.0 # [m] Defines a upper depth range for detections + body_kp_selection: 'FULL' # 'FULL', 'UPPER_BODY' + enable_body_fitting: false # Defines if the body fitting will be applied + enable_tracking: true # Defines if the object detection will track objects across images flow + prediction_timeout_s: 0.5 # During this time [sec], the skeleton will have OK state even if it is not detected. Set this parameter to 0 to disable SDK predictions + confidence_threshold: 50.0 # [DYNAMIC] - Minimum value of the detection confidence of skeleton key points [0,99] + minimum_keypoints_threshold: 5 # [DYNAMIC] - Minimum number of skeleton key points to be detected for a valid skeleton + + stream_server: + stream_enabled: false # enable the streaming server when the camera is open + codec: 'H265' # different encoding types for image streaming: 'H264', 'H265' + port: 30000 # Port used for streaming. Port must be an even number. Any odd number will be rejected. + bitrate: 12500 # [1000 - 60000] Streaming bitrate (in Kbits/s) used for streaming. See https://www.stereolabs.com/docs/api/structsl_1_1StreamingParameters.html#a873ba9440e3e9786eb1476a3bfa536d0 + gop_size: -1 # [max 256] The GOP size determines the maximum distance between IDR/I-frames. Very high GOP size will result in slightly more efficient compression, especially on static scenes. But latency will increase. + adaptative_bitrate: false # Bitrate will be adjusted depending the number of packet dropped during streaming. If activated, the bitrate can vary between [bitrate/4, bitrate]. + chunk_size: 16084 # [1024 - 65000] Stream buffers are divided into X number of chunks where each chunk is chunk_size bytes long. You can lower chunk_size value if network generates a lot of packet lost: this will generates more chunk for a single image, but each chunk sent will be lighter to avoid inside-chunk corruption. Increasing this value can decrease latency. + target_framerate: 0 # Framerate for the streaming output. This framerate must be below or equal to the camera framerate. Allowed framerates are 15, 30, 60 or 100 if possible. Any other values will be discarded and camera FPS will be taken. + + advanced: # WARNING: do not modify unless you are confident of what you are doing + # Reference documentation: https://man7.org/linux/man-pages/man7/sched.7.html + thread_sched_policy: 'SCHED_BATCH' # 'SCHED_OTHER', 'SCHED_BATCH', 'SCHED_FIFO', 'SCHED_RR' - NOTE: 'SCHED_FIFO' and 'SCHED_RR' require 'sudo' + thread_grab_priority: 50 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + thread_sensor_priority: 70 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + thread_pointcloud_priority: 60 # ONLY with 'SCHED_FIFO' and 'SCHED_RR' - [1 (LOW) z-> 99 (HIGH)] - NOTE: 'sudo' required + + debug: + sdk_verbose: 1 # Set the verbose level of the ZED SDK + sdk_verbose_log_file: '' # Path to the file where the ZED SDK will log its messages. If empty, no file will be created. The log level can be set using the `sdk_verbose` parameter. + use_pub_timestamps: false # Use the current ROS time for the message timestamp instead of the camera timestamp. This is useful to test data communication latency. + debug_common: false # Enable/Disable the printing of debug messages related to the common parameters and functionalities + debug_dyn_params: false # Enable/Disable the printing of debug messages related to dynamic parameters updates + debug_grab: false # Enable/Disable the printing of debug messages related to the grab function and thread + debug_sim: false # Enable/Disable the printing of debug messages related to the simulation mode and connection to the simulation server + debug_video_depth: false # Enable/Disable the printing of debug messages related to video and depth parameters and functionalities + debug_camera_controls: false # Enable/Disable the printing of debug messages related to camera controls (exposure, gain, white balance, etc) + debug_point_cloud: false # Enable/Disable the printing of debug messages related to point cloud generation and publishing + debug_tf: false # Enable/Disable the printing of debug messages related to TF broadcasting + debug_positional_tracking: false # Enable/Disable the printing of debug messages related to positional tracking + debug_gnss: false # Enable/Disable the printing of debug messages related to GNSS functionalities + debug_sensors: false # Enable/Disable the printing of debug messages related to sensor data + debug_mapping: false # Enable/Disable the printing of debug messages related to mapping functionalities + debug_terrain_mapping: false # Enable/Disable the printing of debug messages related to terrain mapping functionalities + debug_object_detection: false # Enable/Disable the printing of debug messages related to object detection functionalities + debug_body_tracking: false # Enable/Disable the printing of debug messages related to body tracking functionalities + debug_roi: false # Enable/Disable the printing of debug messages related to region of interest functionalities + debug_streaming: false # Enable/Disable the printing of debug messages related to the network streaming functionalities + debug_advanced: false # Enable/Disable the printing of debug messages related to advanced functionalities + debug_nitros: false # Enable/Disable the printing of debug messages related to NITROS functionalities + disable_nitros: false # If available, disable NITROS usage for debugging and testing purposes diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/custom_object_detection.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/custom_object_detection.yaml new file mode 100644 index 0000000000..370ddce595 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/custom_object_detection.yaml @@ -0,0 +1,1943 @@ +# Example of a custom object detection configuration file for the ZED ROS2 wrapper +# This file is used to configure the CUSTOM object detection parameters for the ZED camera. +# The parameters are defined in a YAML format and can be modified to suit the user's needs. +# The parameters are divided into sections for each CUSTOM object class, with each section containing +# specific parameters for that class. + +# This is an example of configuration file for a custom object detection model trained on the COCO dataset. +# COCO 2017 dataset https://cocodataset.org by Microsoft + +# To create a custom ONNX model, you can follow the online documentation: https://www.stereolabs.com/docs/yolo/export + +/**: + ros__parameters: + object_detection: + custom_onnx_file: '' # Path to the YOLO-like ONNX file for custom object detection directly performed by the ZED SDK + custom_onnx_input_size: 512 # Resolution used with the YOLO-like ONNX file. For example, 512 means a input tensor '1x3x512x512' + + custom_class_count: 80 # Number of classes in the custom ONNX file. For example, 80 for YOLOv8 trained on COCO dataset + + # TODO: Add one instance of each class to the list below + # Note: create a class_XXX identifier for each class in the custom ONNX file. + # Note: XXX is a number from 000 to 'custom_class_count-1', and it must be unique for each class. + # Note: the class_XXX identifier is not required to match the class ID [model_class_id] in the custom ONNX file. + + class_000: + label: 'person' + model_class_id: 0 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_001: + label: 'bicycle' + model_class_id: 1 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_002: + label: 'car' + model_class_id: 2 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_003: + label: 'motorcycle' + model_class_id: 3 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_004: + label: 'airplane' + model_class_id: 4 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_005: + label: 'bus' + model_class_id: 5 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_006: + label: 'train' + model_class_id: 6 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_007: + label: 'truck' + model_class_id: 7 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_008: + label: 'boat' + model_class_id: 8 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_009: + label: 'traffic light' + model_class_id: 9 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_010: + label: 'fire hydrant' + model_class_id: 10 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_011: + label: 'stop sign' + model_class_id: 11 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_012: + label: 'parking meter' + model_class_id: 12 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_013: + label: 'bench' + model_class_id: 13 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_014: + label: 'bird' + model_class_id: 14 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_015: + label: 'cat' + model_class_id: 15 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_016: + label: 'dog' + model_class_id: 16 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_017: + label: 'horse' + model_class_id: 17 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_018: + label: 'sheep' + model_class_id: 18 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_019: + label: 'cow' + model_class_id: 19 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_020: + label: 'elephant' + model_class_id: 20 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_021: + label: 'bear' + model_class_id: 21 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_022: + label: 'zebra' + model_class_id: 22 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_023: + label: 'giraffe' + model_class_id: 23 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_024: + label: 'backpack' + model_class_id: 24 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_025: + label: 'umbrella' + model_class_id: 25 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_026: + label: 'handbag' + model_class_id: 26 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_027: + label: 'tie' + model_class_id: 27 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_028: + label: 'suitcase' + model_class_id: 28 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_029: + label: 'frisbee' + model_class_id: 29 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_030: + label: 'skis' + model_class_id: 30 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_031: + label: 'snowboard' + model_class_id: 31 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_032: + label: 'pesports ballrson' + model_class_id: 32 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_033: + label: 'kite' + model_class_id: 33 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_034: + label: 'baseball bat' + model_class_id: 34 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_035: + label: 'baseball glove' + model_class_id: 35 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_036: + label: 'skateboard' + model_class_id: 36 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_037: + label: 'surfboard' + model_class_id: 37 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_038: + label: 'tennis racket' + model_class_id: 38 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_039: + label: 'bottle' + model_class_id: 39 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_040: + label: 'wine glass' + model_class_id: 40 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_041: + label: 'cup' + model_class_id: 41 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_042: + label: 'fork' + model_class_id: 42 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_043: + label: 'knife' + model_class_id: 43 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_044: + label: 'spoon' + model_class_id: 44 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_045: + label: 'bowl' + model_class_id: 45 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_046: + label: 'banana' + model_class_id: 46 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_047: + label: 'apple' + model_class_id: 47 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_048: + label: 'sandwich' + model_class_id: 48 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_049: + label: 'orange' + model_class_id: 49 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_050: + label: 'broccoli' + model_class_id: 50 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_051: + label: 'carrot' + model_class_id: 51 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_052: + label: 'hot dog' + model_class_id: 52 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_053: + label: 'pizza' + model_class_id: 53 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_054: + label: 'donut' + model_class_id: 54 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_055: + label: 'cake' + model_class_id: 55 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_056: + label: 'chair' + model_class_id: 56 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_057: + label: 'couch' + model_class_id: 57 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_058: + label: 'potted plant' + model_class_id: 58 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_059: + label: 'bed' + model_class_id: 59 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_060: + label: 'dining table' + model_class_id: 60 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_061: + label: 'toilet' + model_class_id: 61 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_062: + label: 'tv' + model_class_id: 62 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_063: + label: 'laptop' + model_class_id: 63 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_064: + label: 'mouse' + model_class_id: 64 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_065: + label: 'remote' + model_class_id: 65 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_066: + label: 'keyboard' + model_class_id: 66 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_067: + label: 'cell phone' + model_class_id: 67 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_068: + label: 'microwave' + model_class_id: 68 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_069: + label: 'oven' + model_class_id: 69 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_070: + label: 'toaster' + model_class_id: 70 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_071: + label: 'sink' + model_class_id: 71 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_072: + label: 'refrigerator' + model_class_id: 72 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_073: + label: 'book' + model_class_id: 73 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_074: + label: 'clock' + model_class_id: 74 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_075: + label: 'vase' + model_class_id: 75 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: true # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: true # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_076: + label: 'scissors' + model_class_id: 76 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_077: + label: 'teddy bear' + model_class_id: 77 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_078: + label: 'hair drier' + model_class_id: 78 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds + + class_079: + label: 'toothbrush' + model_class_id: 79 # Class ID of the object in the custom ONNX file (it is not required that this value matches the value in the 'class_XXX' identifier) + enabled: true # Enable/disable the detection of this class + confidence_threshold: 50.0 # Minimum value of the detection confidence of an object [0,99] + is_grounded: false # Provide hypothesis about the object movements (degrees of freedom or DoF) to improve the object tracking + is_static: false # Provide hypothesis about the object staticity to improve the object tracking + tracking_timeout: -1.0 # Maximum tracking time threshold (in seconds) before dropping the tracked object when unseen for this amount of time + tracking_max_dist: -1.0 # Maximum tracking distance threshold (in meters) before dropping the tracked object when unseen for this amount of meters. Only valid for static object + max_box_width_normalized: -1.0 # Maximum allowed width normalized to the image size + min_box_width_normalized: -1.0 # Minimum allowed width normalized to the image size + max_box_height_normalized: -1.0 # Maximum allowed height normalized to the image size + min_box_height_normalized: -1.0 # Minimum allowed height normalized to the image size + max_box_width_meters: -1.0 # Maximum allowed 3D width + min_box_width_meters: -1.0 # Minimum allowed 3D width + max_box_height_meters: -1.0 # Maximum allowed 3D height + min_box_height_meters: -1.0 # Minimum allowed 3D height + object_acceleration_preset: 'DEFAULT' # Object acceleration preset. Possible values: 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' + max_allowed_acceleration: 100000.0 # If set with a different value from the default [100000], this value takes precedence over the selected preset, allowing for a custom maximum acceleration. Unit is m/s^2. + velocity_smoothing_factor: 0.5 # Control the smoothing of the velocity estimation. Values between 0.0 and 1.0. Default: 0.5 + min_velocity_threshold: 0.2 # Threshold to force an object's velocity to zero. Default: 0.2 m/s + prediction_timeout_s: 0.5 # Duration to keep predicting a track's position after occlusion. Default: 0.5 seconds + min_confirmation_time_s: 0.05 # Minimum confirmation time required to validate a track. Default: 0.05 seconds diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/object_detection.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/object_detection.yaml new file mode 100644 index 0000000000..42a39a7e4d --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/object_detection.yaml @@ -0,0 +1,26 @@ +/**: + ros__parameters: + object_detection: + class: + people: + enabled: true # [DYNAMIC] - Enable/disable the detection of persons + confidence_threshold: 65.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + vehicle: + enabled: true # [DYNAMIC] - Enable/disable the detection of vehicles + confidence_threshold: 60.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + bag: + enabled: true # [DYNAMIC] - Enable/disable the detection of bags + confidence_threshold: 40.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + animal: + enabled: true # [DYNAMIC] - Enable/disable the detection of animals + confidence_threshold: 40.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + electronics: + enabled: true # [DYNAMIC] - Enable/disable the detection of electronic devices + confidence_threshold: 45.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + fruit_vegetable: + enabled: true # [DYNAMIC] - Enable/disable the detection of fruits and vegetables + confidence_threshold: 50.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + sport: + enabled: true # [DYNAMIC] - Enable/disable the detection of sport-related objects + confidence_threshold: 30.0 # [DYNAMIC] - Minimum value of the detection confidence of an object [0,99] + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/virtual.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/virtual.yaml new file mode 100644 index 0000000000..52ecec8b1a --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/virtual.yaml @@ -0,0 +1,27 @@ +# config/zedx.yaml +# Parameters for Stereolabs ZED X camera +--- +/**: + ros__parameters: + general: + camera_model: 'virtual' + camera_name: 'virtual' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. '4K', 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 1000.0 diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed.yaml new file mode 100644 index 0000000000..a466dd24e9 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed.yaml @@ -0,0 +1,19 @@ +# config/zed_yaml +# Parameters for Stereolabs ZED camera +--- +/**: + ros__parameters: + general: + camera_model: 'zed' + camera_name: 'zed' # overwritten by launch file + grab_resolution: 'HD720' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 20.0 diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2.yaml new file mode 100644 index 0000000000..2d39fce487 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2.yaml @@ -0,0 +1,20 @@ +# config/zed2_yaml +# Parameters for Stereolabs ZED2 camera +--- +/**: + ros__parameters: + general: + camera_model: 'zed2' + camera_name: 'zed2' # overwritten by launch file + grab_resolution: 'HD720' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2i.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2i.yaml new file mode 100644 index 0000000000..e07a59b4af --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zed2i.yaml @@ -0,0 +1,21 @@ +# config/zed2i_yaml +# Parameters for Stereolabs zed2i camera + +--- +/**: + ros__parameters: + general: + camera_model: 'zed2i' + camera_name: 'zed2i' # overwritten by launch file + grab_resolution: 'HD1080' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedm.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedm.yaml new file mode 100644 index 0000000000..66319a997b --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedm.yaml @@ -0,0 +1,20 @@ +# config/zedm_yaml +# Parameters for Stereolabs ZED mini camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedm' + camera_name: 'zedm' # overwritten by launch file + grab_resolution: 'HD1080' # The native camera grab resolution. 'HD2K', 'HD1080', 'HD720', 'VGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate + + video: + brightness: 4 # [DYNAMIC] Image brightness. Range: 0-8 + contrast: 4 # [DYNAMIC] Image contrast. Range: 0-8 + hue: 0 # [DYNAMIC] Image hue. Range: 0 to 11 + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 15.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedx.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedx.yaml new file mode 100644 index 0000000000..897b76af54 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedx.yaml @@ -0,0 +1,28 @@ +# config/zedx.yaml +# Parameters for Stereolabs ZED X camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedx' + camera_name: 'zedx' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 40.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdr.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdr.yaml new file mode 100644 index 0000000000..3cf417568c --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdr.yaml @@ -0,0 +1,28 @@ +# config/zedxhdr.yaml +# Parameters for Stereolabs ZED X HDR camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxhdr' + camera_name: 'zedxhdr' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 15.0 # Min: 0.5, Max: 40.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmax.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmax.yaml new file mode 100644 index 0000000000..85df02e0e1 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmax.yaml @@ -0,0 +1,28 @@ +# config/zedxhdrmax.yaml +# Parameters for Stereolabs ZED X HDR MAX camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxhdrmax' + camera_name: 'zedxhdrmax' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 20.0 # Min: 0.5, Max: 40.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmini.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmini.yaml new file mode 100644 index 0000000000..39200c2d0c --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxhdrmini.yaml @@ -0,0 +1,28 @@ +# config/zedxhdrmini.yaml +# Parameters for Stereolabs ZED X HDR MINI camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxhdrmini' + camera_name: 'zedxhdrmini' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) + + video: + exposure_time: 16000 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 30000 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 1255 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 1 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxm.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxm.yaml new file mode 100644 index 0000000000..833b5dffae --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxm.yaml @@ -0,0 +1,28 @@ +# config/zedxm_yaml +# Parameters for Stereolabs ZED X Mini camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxm' + camera_name: 'zedxm' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + exposure_time: 16666 # Defines the real exposure time in microseconds. Recommended to control manual exposure (instead of `video.exposure` setting) + auto_exposure_time_range_min: 28 # Defines the minimum range of exposure auto control in micro seconds + auto_exposure_time_range_max: 16666 # Defines the maximum range of exposure auto control in micro seconds + exposure_compensation: 50 # Defines the Exposure-target compensation made after auto exposure. Reduces the overall illumination target by factor of F-stops. Values range is [0 - 100]. Default value is 50, i.e. no compensation applied + analog_gain: 8000 # Defines the real analog gain (sensor) in mDB. Range [1000-16000]. Recommended to control manual sensor gain (instead of `video.gain` setting) + auto_analog_gain_range_min: 1000 # Defines the minimum range of sensor gain in automatic control + auto_analog_gain_range_max: 16000 # Defines the maximum range of sensor gain in automatic control + digital_gain: 128 # Defines the real digital gain (ISP) as a factor. Range [1-256]. Recommended to control manual ISP gain (instead of `video.gain` setting) + auto_digital_gain_range_min: 1 # Defines the minimum range of digital ISP gain in automatic control + auto_digital_gain_range_max: 256 # Defines the maximum range of digital ISP gain in automatic control + denoising: 50 # Defines the level of denoising applied on both left and right images. Range [0-100] + + depth: + min_depth: 0.01 # Min: 0.01, Max: 3.0 + max_depth: 10.0 # Min: 0.5, Max: 20.0 + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxone4k.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxone4k.yaml new file mode 100644 index 0000000000..a8efcaa887 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxone4k.yaml @@ -0,0 +1,14 @@ +# config/zedxone4k.yaml +# Parameters for Stereolabs ZED X One 4K camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxone4k' + camera_name: 'zedxone4k' # overwritten by launch file + grab_resolution: 'QHDPLUS' # The native camera grab resolution. 'HD4K', 'HD1200', 'QHDPLUS, 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD4K/QHDPLUS: 15 - HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) + + video: + enable_hdr: false # When set to true, the camera will be set in HDR mode if the camera model and resolution allows it + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonegs.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonegs.yaml new file mode 100644 index 0000000000..f4d08b0026 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonegs.yaml @@ -0,0 +1,10 @@ +# config/zedxonegs.yaml +# Parameters for Stereolabs ZED X One GS camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxonegs' + camera_name: 'zedxonegs' # overwritten by launch file + grab_resolution: 'HD1200' # The native camera grab resolution. 'HD1200', 'HD1080', 'SVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1200/HD1080: 60, 30, 15 - SVGA: 120, 60, 30, 15) \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonehdr.yaml b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonehdr.yaml new file mode 100644 index 0000000000..e9f756744d --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/config/zedxonehdr.yaml @@ -0,0 +1,10 @@ +# config/zedxonehdr.yaml +# Parameters for Stereolabs ZED X One HDR camera +--- +/**: + ros__parameters: + general: + camera_model: 'zedxonehdr' + camera_name: 'zedxonehdr' # overwritten by launch file + grab_resolution: 'HD1536' # The native camera grab resolution. 'HD1536', 'XVGA', 'AUTO' + grab_frame_rate: 30 # ZED SDK internal grabbing rate (HD1536: 30, XVGA: 30) \ No newline at end of file diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/launch/zed_camera.launch.py b/src/lib/zed-ros2-wrapper/zed_wrapper/launch/zed_camera.launch.py new file mode 100644 index 0000000000..d2469bb94d --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/launch/zed_camera.launch.py @@ -0,0 +1,604 @@ +# Copyright 2025 Stereolabs +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an 'AS IS' BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys +import yaml + +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch.actions import ( + DeclareLaunchArgument, + OpaqueFunction, + LogInfo +) +from launch.conditions import IfCondition +from launch.substitutions import ( + LaunchConfiguration, + Command, + TextSubstitution +) +from launch_ros.actions import ( + Node, + ComposableNodeContainer, + LoadComposableNodes +) +from launch_ros.descriptions import ComposableNode + +# Enable colored output +os.environ["RCUTILS_COLORIZED_OUTPUT"] = "1" + +# ZED Configurations to be loaded by ZED Node +default_config_common = os.path.join( + get_package_share_directory('zed_wrapper'), + 'config', + 'common' +) + +# Object Detection Configuration to be loaded by ZED Node +default_object_detection_config_path = os.path.join( + get_package_share_directory('zed_wrapper'), + 'config', + 'object_detection.yaml' +) +# Custom Object Detection Configuration to be loaded by ZED Node +default_custom_object_detection_config_path = os.path.join( + get_package_share_directory('zed_wrapper'), + 'config', + 'custom_object_detection.yaml' +) + +# URDF/xacro file to be loaded by the Robot State Publisher node +default_xacro_path = os.path.join( + get_package_share_directory('zed_description'), + 'urdf', + 'zed_descr.urdf.xacro' +) + +# Function to parse array-like launch arguments +def parse_array_param(param): + cleaned = param.replace('[', '').replace(']', '').replace(' ', '') + if not cleaned: + return [] + return cleaned.split(',') + + +def _auto_type(value): + """Convert a string value to the most appropriate Python type.""" + lowered = value.strip().lower() + if lowered == 'true': + return True + if lowered == 'false': + return False + try: + return int(value) + except ValueError: + pass + try: + return float(value) + except ValueError: + pass + return value + + +def _parse_param_overrides(overrides_str): + """Parse semicolon-separated 'key:=value' pairs into a dict.""" + result = {} + if not overrides_str: + return result + for pair in overrides_str.split(';'): + pair = pair.strip() + if ':=' in pair: + key, value = pair.split(':=', 1) + result[key.strip()] = _auto_type(value.strip()) + return result + + +def _to_bool(value): + if isinstance(value, bool): + return value + + if isinstance(value, str): + lowered = value.strip().lower() + if lowered == 'true': + return True + if lowered == 'false': + return False + + return None + + +def _find_disable_nitros(node): + if isinstance(node, dict): + ros_params = node.get('ros__parameters') + if isinstance(ros_params, dict): + debug_section = ros_params.get('debug') + if isinstance(debug_section, dict) and 'disable_nitros' in debug_section: + return _to_bool(debug_section['disable_nitros']) + + for value in node.values(): + found = _find_disable_nitros(value) + if found is not None: + return found + + return None + + +def _get_disable_nitros_from_file(file_path): + if not file_path or not os.path.isfile(file_path): + return None + + try: + with open(file_path, 'r', encoding='utf-8') as yaml_file: + data = yaml.safe_load(yaml_file) + + if data is None: + return None + + return _find_disable_nitros(data) + except Exception: + return None + +def launch_setup(context, *args, **kwargs): + return_array = [] + + # Launch configuration variables + node_log_type = LaunchConfiguration('node_log_type') + + svo_path = LaunchConfiguration('svo_path') + publish_svo_clock = LaunchConfiguration('publish_svo_clock') + + enable_ipc = LaunchConfiguration('enable_ipc') + ipc_nitros_conflict_policy = LaunchConfiguration('ipc_nitros_conflict_policy') + use_sim_time = LaunchConfiguration('use_sim_time') + sim_mode = LaunchConfiguration('sim_mode') + sim_address = LaunchConfiguration('sim_address') + sim_port = LaunchConfiguration('sim_port') + + stream_address = LaunchConfiguration('stream_address') + stream_port = LaunchConfiguration('stream_port') + + container_name = LaunchConfiguration('container_name') + namespace = LaunchConfiguration('namespace') + camera_name = LaunchConfiguration('camera_name') + camera_model = LaunchConfiguration('camera_model') + + node_name = LaunchConfiguration('node_name') + + ros_params_override_path = LaunchConfiguration('ros_params_override_path') + object_detection_config_path = LaunchConfiguration('object_detection_config_path') + custom_object_detection_config_path = LaunchConfiguration('custom_object_detection_config_path') + param_overrides = LaunchConfiguration('param_overrides') + + serial_number = LaunchConfiguration('serial_number') + camera_id = LaunchConfiguration('camera_id') + + serial_numbers = LaunchConfiguration('serial_numbers') + camera_ids = LaunchConfiguration('camera_ids') + + publish_urdf = LaunchConfiguration('publish_urdf') + publish_tf = LaunchConfiguration('publish_tf') + publish_map_tf = LaunchConfiguration('publish_map_tf') + publish_imu_tf = LaunchConfiguration('publish_imu_tf') + xacro_path = LaunchConfiguration('xacro_path') + + enable_gnss = LaunchConfiguration('enable_gnss') + gnss_antenna_offset = LaunchConfiguration('gnss_antenna_offset') + + node_log_type_val = node_log_type.perform(context) + container_name_val = container_name.perform(context) + namespace_val = namespace.perform(context) + camera_name_val = camera_name.perform(context) + camera_model_val = camera_model.perform(context) + node_name_val = node_name.perform(context) + enable_gnss_val = enable_gnss.perform(context) + gnss_coords = parse_array_param(gnss_antenna_offset.perform(context)) + serial_numbers_val = serial_numbers.perform(context) + camera_ids_val = camera_ids.perform(context) + + stereo_models = ( + 'zed', 'zedm', 'zed2', 'zed2i', + 'zedx', 'zedxm', + 'zedxhdr', 'zedxhdrmini', 'zedxhdrmax', + 'virtual' + ) + is_stereo_model = camera_model_val in stereo_models + + if(node_log_type_val == 'both'): + node_log_effective = 'both' + else: # 'screen' or 'log' + node_log_effective = { + 'stdout': node_log_type_val, + 'stderr': node_log_type_val + } + + if (camera_name_val == ''): + camera_name_val = 'zed' + + if (camera_model_val == 'virtual'): + # Virtual Stereo Camera setup + serials = parse_array_param(serial_numbers_val) + ids = parse_array_param(camera_ids_val) + + # If not in live mode, at least one of serials or ids must be a valid 2-values array + if(len(serials) != 2 and len(ids) != 2 and svo_path.perform(context) == 'live'): + return [ + LogInfo(msg=TextSubstitution( + text='With a Virtual Stereo Camera setup, one of `serial_numbers` or `camera_ids` launch arguments must contain two valid values (Left and Right camera identification).')) + ] + + if(namespace_val == ''): + namespace_val = camera_name_val + else: + node_name_val = camera_name_val + + # Common configuration file + if is_stereo_model: + config_common_path_val = default_config_common + '_stereo.yaml' + else: + config_common_path_val = default_config_common + '_mono.yaml' + + info = 'Using common configuration file: ' + config_common_path_val + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # Camera configuration file + config_camera_path = os.path.join( + get_package_share_directory('zed_wrapper'), + 'config', + camera_model_val + '.yaml' + ) + + info = 'Using camera configuration file: ' + config_camera_path + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # Object Detection configuration file + info = 'Using Object Detection configuration file: ' + object_detection_config_path.perform(context) + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # Custom Object Detection configuration file + info = 'Using Custom Object Detection configuration file: ' + custom_object_detection_config_path.perform(context) + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + # ROS parameters override file + ros_params_override_path_val = ros_params_override_path.perform(context) + if(ros_params_override_path_val != ''): + info = 'Using ROS parameters override file: ' + ros_params_override_path_val + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + enable_ipc_effective = enable_ipc.perform(context) == 'true' + ipc_nitros_conflict_policy_val = ipc_nitros_conflict_policy.perform(context) + + # Effective `debug.disable_nitros` value from loaded YAML files. + # Component defaults differ if parameter is not present. + # - ZedCamera (stereo/virtual): default true + # - ZedCameraOne (mono): default false + nitros_disabled_effective = True if is_stereo_model else False + + common_disable_nitros = _get_disable_nitros_from_file(config_common_path_val) + if common_disable_nitros is not None: + nitros_disabled_effective = common_disable_nitros + + if ros_params_override_path_val != '': + override_disable_nitros = _get_disable_nitros_from_file(ros_params_override_path_val) + if override_disable_nitros is not None: + nitros_disabled_effective = override_disable_nitros + + # Parse inline parameter overrides from command line + param_overrides_dict = _parse_param_overrides(param_overrides.perform(context)) + + # Check if disable_nitros is set via inline overrides + inline_disable_nitros = _to_bool(param_overrides_dict.get('debug.disable_nitros')) + if inline_disable_nitros is not None: + nitros_disabled_effective = inline_disable_nitros + + if enable_ipc_effective and not nitros_disabled_effective: + conflict_msg = ( + 'Invalid configuration: `enable_ipc:=true` with ' + '`debug.disable_nitros:=false` can cause NITROS startup failure ' + '(volatile durability conflict).' + ) + + if ipc_nitros_conflict_policy_val == 'disable_ipc': + enable_ipc_effective = False + return_array.append(LogInfo(msg=TextSubstitution( + text='WARNING: ' + conflict_msg + ' Forcing `enable_ipc:=false` for this launch.'))) + else: + raise RuntimeError(conflict_msg + ' Set `enable_ipc:=false` or `debug.disable_nitros:=true`.') + + # Xacro command with options + xacro_command = [] + xacro_command.append('xacro') + xacro_command.append(' ') + xacro_command.append(xacro_path.perform(context)) + xacro_command.append(' ') + xacro_command.append('camera_name:=') + xacro_command.append(camera_name_val) + xacro_command.append(' ') + xacro_command.append('camera_model:=') + xacro_command.append(camera_model_val) + xacro_command.append(' ') + if(enable_gnss_val=='true'): + xacro_command.append(' ') + xacro_command.append('enable_gnss:=true') + xacro_command.append(' ') + if(len(gnss_coords)==3): + xacro_command.append('gnss_x:=') + xacro_command.append(gnss_coords[0]) + xacro_command.append(' ') + xacro_command.append('gnss_y:=') + xacro_command.append(gnss_coords[1]) + xacro_command.append(' ') + xacro_command.append('gnss_z:=') + xacro_command.append(gnss_coords[2]) + xacro_command.append(' ') + + # Robot State Publisher node + rsp_name = camera_name_val + '_state_publisher' + rsp_node = Node( + condition=IfCondition(publish_urdf), + package='robot_state_publisher', + namespace=namespace_val, + executable='robot_state_publisher', + name=rsp_name, + output=node_log_effective, + parameters=[{ + 'use_sim_time': publish_svo_clock, + 'robot_description': Command(xacro_command) + }], + remappings=[('robot_description', camera_name_val+'_description')] + ) + return_array.append(rsp_node) + + # ROS 2 Component Container + if(container_name_val == ''): + container_name_val='zed_container' + distro = os.environ['ROS_DISTRO'] + if distro == 'foxy': + # Foxy does not support the isolated mode + container_exec='component_container' + arguments_val=['--ros-args', '--log-level', 'info'] + else: + container_exec='component_container_isolated' + arguments_val=['--use_multi_threaded_executor','--ros-args', '--log-level', 'info'] + #arguments_val=['--use_multi_threaded_executor','--ros-args', '--log-level', 'debug'] + + zed_container = ComposableNodeContainer( + name=container_name_val, + namespace=namespace_val, + package='rclcpp_components', + executable=container_exec, + arguments=arguments_val, + output=node_log_effective, + composable_node_descriptions=[] + ) + return_array.append(zed_container) + + # ZED Node parameters + node_parameters = [ + # YAML files + config_common_path_val, # Common parameters + config_camera_path, # Camera related parameters + object_detection_config_path, # Object detection parameters + custom_object_detection_config_path # Custom object detection parameters + ] + + if( ros_params_override_path_val != ''): + node_parameters.append(ros_params_override_path) + + node_parameters.append( + # Launch arguments must override the YAML files values + { + 'use_sim_time': use_sim_time, + 'simulation.sim_enabled': sim_mode, + 'simulation.sim_address': sim_address, + 'simulation.sim_port': sim_port, + 'stream.stream_address': stream_address, + 'stream.stream_port': stream_port, + 'general.camera_name': camera_name_val, + 'general.camera_model': camera_model_val, + 'svo.svo_path': svo_path, + 'svo.publish_svo_clock': publish_svo_clock, + 'general.serial_number': serial_number, + 'general.camera_id': camera_id, + 'pos_tracking.publish_tf': publish_tf, + 'pos_tracking.publish_map_tf': publish_map_tf, + 'sensors.publish_imu_tf': publish_imu_tf, + 'gnss_fusion.gnss_fusion_enabled': enable_gnss, + 'general.virtual_serial_numbers': serial_numbers_val, + 'general.virtual_camera_ids': camera_ids_val + } + ) + + # Append inline parameter overrides (highest priority) + if param_overrides_dict: + node_parameters.append(param_overrides_dict) + + # ZED Wrapper component + if is_stereo_model: + zed_wrapper_component = ComposableNode( + package='zed_components', + namespace=namespace_val, + plugin='stereolabs::ZedCamera', + name=node_name_val, + parameters=node_parameters, + extra_arguments=[{'use_intra_process_comms': enable_ipc_effective}] + ) + else: # camera_model_val == 'zedxonegs' or camera_model_val == 'zedxone4k' or camera_model_val == 'zedxonehdr' + zed_wrapper_component = ComposableNode( + package='zed_components', + namespace=namespace_val, + plugin='stereolabs::ZedCameraOne', + name=node_name_val, + parameters=node_parameters, + extra_arguments=[{'use_intra_process_comms': enable_ipc_effective}] + ) + + full_container_name = '/' + namespace_val + '/' + container_name_val + info = 'Loading ZED node `' + node_name_val + '` in container `' + full_container_name + '`' + return_array.append(LogInfo(msg=TextSubstitution(text=info))) + + load_composable_node = LoadComposableNodes( + target_container=full_container_name, + composable_node_descriptions=[zed_wrapper_component] + ) + return_array.append(load_composable_node) + + return return_array + +def generate_launch_description(): + return LaunchDescription( + [ + # Declare launch arguments + DeclareLaunchArgument( + 'node_log_type', + default_value=TextSubstitution(text='both'), + description='The log type of the node. It can be `screen`, `log` or `both`. The `log` type will save the log in a file in the `~/.ros/log/` folder. The `screen` type will print the log on the terminal. The `both` type will do both.', + choices=['screen', 'log', 'both']), + DeclareLaunchArgument( + 'camera_name', + default_value=TextSubstitution(text='zed'), + description='The name of the camera. It can be different from the camera model and it will be used as node `namespace`.'), + DeclareLaunchArgument( + 'camera_model', + description='[REQUIRED] The model of the camera. Using a wrong camera model can disable camera features.', + choices=['zed', 'zedm', 'zed2', 'zed2i', 'zedx', 'zedxm', 'zedxhdr', 'zedxhdrmini', 'zedxhdrmax', 'virtual', 'zedxonegs', 'zedxone4k', 'zedxonehdr']), + DeclareLaunchArgument( + 'container_name', + default_value='', + description='The name of the container to be used to load the ZED component. If empty (default) a new container will be created.'), + DeclareLaunchArgument( + 'namespace', + default_value='', + description='The namespace of the node. If empty (default) the camera name is used.'), + DeclareLaunchArgument( + 'node_name', + default_value='zed_node', + description='The name of the zed_wrapper node. All the topic will have the same prefix: `///`. If a namespace is specified, the node name is replaced by the camera name.'), + DeclareLaunchArgument( + 'ros_params_override_path', + default_value='', + description='The path to an additional parameters file to override the default values.'), + DeclareLaunchArgument( + 'object_detection_config_path', + default_value=TextSubstitution(text=default_object_detection_config_path), + description='Path to the YAML configuration file for the Object Detection parameters.'), + DeclareLaunchArgument( + 'custom_object_detection_config_path', + default_value=TextSubstitution(text=default_custom_object_detection_config_path), + description='Path to the YAML configuration file for the Custom Object Detection parameters.'), + DeclareLaunchArgument( + 'serial_number', + default_value='0', + description='The serial number of the camera to be opened. It is mandatory to use this parameter or camera ID in multi-camera rigs to distinguish between different cameras. Use `ZED_Explorer -a` to retrieve the serial number of all the connected cameras.'), + DeclareLaunchArgument( + 'serial_numbers', + default_value='[]', + description='The serial numbers of the two cameras to be opened to compose a Virtual Stereo Camera, [left_sn,right_sn]. Use `ZED_Explorer -a` to retrieve the serial number of all the connected cameras.'), + DeclareLaunchArgument( + 'camera_id', + default_value='-1', + description='The ID of the camera to be opened. It is mandatory to use this parameter or serial number in multi-camera rigs to distinguish between different cameras. Use `ZED_Explorer -a` to retrieve the ID of all the connected cameras.'), + DeclareLaunchArgument( + 'camera_ids', + default_value='[]', + description='The IDs of the two cameras to be opened to compose a Virtual Stereo Camera, [left_id,right_id]. Use `ZED_Explorer -a` to retrieve the ID of all the connected cameras.'), + DeclareLaunchArgument( + 'publish_urdf', + default_value='true', + description='Enable URDF processing and starts Robot State Published to propagate static TF.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'publish_tf', + default_value='true', + description='Enable publication of the `odom -> camera_link` TF.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'publish_map_tf', + default_value='true', + description='Enable publication of the `map -> odom` TF. Note: Ignored if `publish_tf` is False.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'publish_imu_tf', + default_value='false', + description='Enable publication of the IMU TF. Note: Ignored if `publish_tf` is False.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'xacro_path', + default_value=TextSubstitution(text=default_xacro_path), + description='Path to the camera URDF file as a xacro file.'), + DeclareLaunchArgument( + 'svo_path', + default_value=TextSubstitution(text='live'), + description='Path to an input SVO file.'), + DeclareLaunchArgument( + 'publish_svo_clock', + default_value='false', + description='If set to `true` the node will act as a clock server publishing the SVO timestamp. This is useful for node synchronization'), + DeclareLaunchArgument( + 'enable_gnss', + default_value='false', + description='Enable GNSS fusion to fix positional tracking pose with GNSS data from messages of type `sensor_msgs::msg::NavSatFix`. The fix topic can be customized in `common_stereo.yaml`.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'gnss_antenna_offset', + default_value='[]', + description='Position of the GNSS antenna with respect to the mounting point of the ZED camera. Format: [x,y,z]'), + DeclareLaunchArgument( + 'enable_ipc', + default_value='true', + description='Enable intra-process communication (IPC) with ROS 2 Composition', + choices=['true', 'false']), + DeclareLaunchArgument( + 'ipc_nitros_conflict_policy', + default_value='disable_ipc', + description='Behavior when IPC is enabled and NITROS is enabled (`debug.disable_nitros:=false`). ' + '`disable_ipc`: force IPC off for this launch. ' + '`exit`: stop launch with an error.', + choices=['disable_ipc', 'exit']), + DeclareLaunchArgument( + 'use_sim_time', + default_value='false', + description='If set to `true` the node will wait for messages on the `/clock` topic to start and will use this information as the timestamp reference', + choices=['true', 'false']), + DeclareLaunchArgument( + 'sim_mode', + default_value='false', + description='Enable simulation mode. Set `sim_address` and `sim_port` to configure the simulator input.', + choices=['true', 'false']), + DeclareLaunchArgument( + 'sim_address', + default_value='127.0.0.1', + description='The connection address of the simulation server. See the documentation of the supported simulation plugins for more information.'), + DeclareLaunchArgument( + 'sim_port', + default_value='30000', + description='The connection port of the simulation server. See the documentation of the supported simulation plugins for more information.'), + DeclareLaunchArgument( + 'stream_address', + default_value='', + description='The connection address of the input streaming server.'), + DeclareLaunchArgument( + 'stream_port', + default_value='30000', + description='The connection port of the input streaming server.'), + DeclareLaunchArgument( + 'param_overrides', + default_value='', + description='Inline parameter overrides as semicolon-separated key:=value pairs. ' + 'These have the highest priority and override all YAML and launch argument values. ' + 'Example: "debug.disable_nitros:=true;object_detection.custom_onnx_file:=/path/to/model.onnx"'), + OpaqueFunction(function=launch_setup) + ] + ) diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/package.xml b/src/lib/zed-ros2-wrapper/zed_wrapper/package.xml new file mode 100644 index 0000000000..a081ea434b --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/package.xml @@ -0,0 +1,38 @@ + + + + zed_wrapper + 5.2.2 + zed_wrapper loading zed_components in a single process + STEREOLABS + Apache License 2.0 + https://www.stereolabs.com/ + https://github.com/stereolabs/zed-ros2-wrapper + https://github.com/stereolabs/zed-ros2-wrapper/issues + + ament_cmake + + ament_cmake_auto + + zed_components + + launch_ros + zed_description + xacro + image_transport_plugins + compressed_image_transport + compressed_depth_image_transport + theora_image_transport + + ament_lint_auto + ament_cmake_copyright + ament_cmake_cppcheck + ament_cmake_lint_cmake + ament_cmake_pep257 + ament_cmake_uncrustify + ament_cmake_xmllint + + + ament_cmake + + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_descr.urdf.xacro b/src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_descr.urdf.xacro new file mode 100644 index 0000000000..213af56fd8 --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_descr.urdf.xacro @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_macro.urdf.xacro b/src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_macro.urdf.xacro new file mode 100644 index 0000000000..bcb065b27e --- /dev/null +++ b/src/lib/zed-ros2-wrapper/zed_wrapper/urdf/zed_macro.urdf.xacro @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +