diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/amber.png b/amber.png new file mode 100644 index 0000000000..2cab170d83 Binary files /dev/null and b/amber.png differ diff --git a/badge.svg b/badge.svg new file mode 100644 index 0000000000..0a1f6cf0fc --- /dev/null +++ b/badge.svg @@ -0,0 +1 @@ +test coveragetest coverage60.4%60.4% \ No newline at end of file diff --git a/emerald.png b/emerald.png new file mode 100644 index 0000000000..38ad4f4068 Binary files /dev/null and b/emerald.png differ diff --git a/gcov.css b/gcov.css new file mode 100644 index 0000000000..bfd0a83e10 --- /dev/null +++ b/gcov.css @@ -0,0 +1,519 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #FFFFFF; +} + +/* All views: standard link format*/ +a:link +{ + color: #284FA8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00CB40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #FF0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #DAE7FE; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #A7FC9D; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FFEA20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FF0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688D4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #FFFFFF; + background-color: #6688D4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #FFFFFF; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #DAE7FE; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #EFE383; +} + +/* Source code view: format for lines which were executed */ +td.lineCov, +span.lineCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #CAD7FE; +} + +/* Source code view: format for lines which were not executed */ +td.lineNoCov, +span.lineNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #FF6230; +} + +/* Source code view (function table): standard link - visited format */ +td.lineNoCov > a:visited, +td.lineCov > a:visited +{ + color: black; + text-decoration: underline; +} + +/* Source code view: format for lines which were executed only in a + previous version */ +span.lineDiffCov +{ + background-color: #B5F7AF; +} + +/* Source code view: format for branches which were executed + * and taken */ +span.branchCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for branches which were executed + * but not taken */ +span.branchNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for branches which were not executed */ +span.branchNoExec +{ + background-color: #FF6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #FF0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #FFEA20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #A7FC9D; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FF0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FFEA20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #A7FC9D; +} diff --git a/glass.png b/glass.png new file mode 100644 index 0000000000..e1abc00680 Binary files /dev/null and b/glass.png differ diff --git a/index-sort-f.html b/index-sort-f.html new file mode 100644 index 0000000000..67428ea1a8 --- /dev/null +++ b/index-sort-f.html @@ -0,0 +1,313 @@ + + + + + + + LCOV - coverage.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:coverage.infoLines:55031026453.6 %
Date:2023-11-29 14:09:54Functions:59097760.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mrs_lib/src/geometry +
14.2%14.2%
+
14.2 %63 / 44513.8 %13 / 94
mrs_uav_managers/include/mrs_uav_managers/control_manager +
13.5%13.5%
+
13.5 %13 / 9618.5 %5 / 27
mrs_uav_managers/include/control_manager +
100.0%
+
100.0 %4 / 430.0 %3 / 10
mrs_uav_managers/src/control_manager/common +
27.9%27.9%
+
27.9 %157 / 56338.7 %12 / 31
mrs_lib/include/mrs_lib/geometry +
69.9%69.9%
+
69.9 %65 / 9339.2 %47 / 120
mrs_uav_managers/include/mrs_uav_managers +
100.0%
+
100.0 %1 / 150.0 %1 / 2
mrs_uav_managers/src/control_manager +
46.4%46.4%
+
46.4 %1723 / 371252.0 %64 / 123
mrs_uav_managers/include/transform_manager +
47.1%47.1%
+
47.1 %186 / 39557.9 %11 / 19
mrs_lib/src/transformer +
58.9%58.9%
+
58.9 %165 / 28065.4 %17 / 26
mrs_lib/include/mrs_lib/impl +
72.1%72.1%
+
72.1 %289 / 40168.2 %75 / 110
mrs_uav_managers/src +
55.1%55.1%
+
55.1 %931 / 169072.6 %53 / 73
mrs_uav_managers/src/transform_manager +
63.1%63.1%
+
63.1 %275 / 43676.9 %10 / 13
mrs_uav_managers/src/estimation_manager +
63.8%63.8%
+
63.8 %391 / 61378.7 %37 / 47
mrs_lib/include/mrs_lib +
78.7%78.7%
+
78.7 %570 / 72481.0 %132 / 163
mrs_lib/src/timeout_manager +
79.0%79.0%
+
79.0 %49 / 6281.8 %9 / 11
mrs_uav_managers/include/mrs_uav_managers/estimation_manager +
81.0%81.0%
+
81.0 %85 / 10586.7 %13 / 15
mrs_lib/src/attitude_converter +
91.1%91.1%
+
91.1 %204 / 22490.2 %37 / 41
mrs_lib/src/median_filter +
89.1%89.1%
+
89.1 %82 / 9294.1 %16 / 17
mrs_lib/src/math +
100.0%
+
100.0 %17 / 17100.0 %1 / 1
mrs_lib/src/utils +
100.0%
+
100.0 %7 / 7100.0 %2 / 2
mrs_lib/src/param_loader +
70.9%70.9%
+
70.9 %39 / 55100.0 %4 / 4
mrs_uav_managers/src/estimation_manager/estimators +
60.7%60.7%
+
60.7 %82 / 135100.0 %13 / 13
mrs_lib/src/timer +
92.1%92.1%
+
92.1 %105 / 114100.0 %15 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/index-sort-l.html b/index-sort-l.html new file mode 100644 index 0000000000..c3c8cc1900 --- /dev/null +++ b/index-sort-l.html @@ -0,0 +1,313 @@ + + + + + + + LCOV - coverage.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:coverage.infoLines:55031026453.6 %
Date:2023-11-29 14:09:54Functions:59097760.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mrs_uav_managers/include/mrs_uav_managers/control_manager +
13.5%13.5%
+
13.5 %13 / 9618.5 %5 / 27
mrs_lib/src/geometry +
14.2%14.2%
+
14.2 %63 / 44513.8 %13 / 94
mrs_uav_managers/src/control_manager/common +
27.9%27.9%
+
27.9 %157 / 56338.7 %12 / 31
mrs_uav_managers/src/control_manager +
46.4%46.4%
+
46.4 %1723 / 371252.0 %64 / 123
mrs_uav_managers/include/transform_manager +
47.1%47.1%
+
47.1 %186 / 39557.9 %11 / 19
mrs_uav_managers/src +
55.1%55.1%
+
55.1 %931 / 169072.6 %53 / 73
mrs_lib/src/transformer +
58.9%58.9%
+
58.9 %165 / 28065.4 %17 / 26
mrs_uav_managers/src/estimation_manager/estimators +
60.7%60.7%
+
60.7 %82 / 135100.0 %13 / 13
mrs_uav_managers/src/transform_manager +
63.1%63.1%
+
63.1 %275 / 43676.9 %10 / 13
mrs_uav_managers/src/estimation_manager +
63.8%63.8%
+
63.8 %391 / 61378.7 %37 / 47
mrs_lib/include/mrs_lib/geometry +
69.9%69.9%
+
69.9 %65 / 9339.2 %47 / 120
mrs_lib/src/param_loader +
70.9%70.9%
+
70.9 %39 / 55100.0 %4 / 4
mrs_lib/include/mrs_lib/impl +
72.1%72.1%
+
72.1 %289 / 40168.2 %75 / 110
mrs_lib/include/mrs_lib +
78.7%78.7%
+
78.7 %570 / 72481.0 %132 / 163
mrs_lib/src/timeout_manager +
79.0%79.0%
+
79.0 %49 / 6281.8 %9 / 11
mrs_uav_managers/include/mrs_uav_managers/estimation_manager +
81.0%81.0%
+
81.0 %85 / 10586.7 %13 / 15
mrs_lib/src/median_filter +
89.1%89.1%
+
89.1 %82 / 9294.1 %16 / 17
mrs_lib/src/attitude_converter +
91.1%91.1%
+
91.1 %204 / 22490.2 %37 / 41
mrs_lib/src/timer +
92.1%92.1%
+
92.1 %105 / 114100.0 %15 / 15
mrs_uav_managers/include/mrs_uav_managers +
100.0%
+
100.0 %1 / 150.0 %1 / 2
mrs_uav_managers/include/control_manager +
100.0%
+
100.0 %4 / 430.0 %3 / 10
mrs_lib/src/utils +
100.0%
+
100.0 %7 / 7100.0 %2 / 2
mrs_lib/src/math +
100.0%
+
100.0 %17 / 17100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/index.html b/index.html new file mode 100644 index 0000000000..fe0a4cea72 --- /dev/null +++ b/index.html @@ -0,0 +1,313 @@ + + + + + + + LCOV - coverage.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:coverage.infoLines:55031026453.6 %
Date:2023-11-29 14:09:54Functions:59097760.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
mrs_lib/include/mrs_lib +
78.7%78.7%
+
78.7 %570 / 72481.0 %132 / 163
mrs_lib/include/mrs_lib/geometry +
69.9%69.9%
+
69.9 %65 / 9339.2 %47 / 120
mrs_lib/include/mrs_lib/impl +
72.1%72.1%
+
72.1 %289 / 40168.2 %75 / 110
mrs_lib/src/attitude_converter +
91.1%91.1%
+
91.1 %204 / 22490.2 %37 / 41
mrs_lib/src/geometry +
14.2%14.2%
+
14.2 %63 / 44513.8 %13 / 94
mrs_lib/src/math +
100.0%
+
100.0 %17 / 17100.0 %1 / 1
mrs_lib/src/median_filter +
89.1%89.1%
+
89.1 %82 / 9294.1 %16 / 17
mrs_lib/src/param_loader +
70.9%70.9%
+
70.9 %39 / 55100.0 %4 / 4
mrs_lib/src/timeout_manager +
79.0%79.0%
+
79.0 %49 / 6281.8 %9 / 11
mrs_lib/src/timer +
92.1%92.1%
+
92.1 %105 / 114100.0 %15 / 15
mrs_lib/src/transformer +
58.9%58.9%
+
58.9 %165 / 28065.4 %17 / 26
mrs_lib/src/utils +
100.0%
+
100.0 %7 / 7100.0 %2 / 2
mrs_uav_managers/include/control_manager +
100.0%
+
100.0 %4 / 430.0 %3 / 10
mrs_uav_managers/include/mrs_uav_managers +
100.0%
+
100.0 %1 / 150.0 %1 / 2
mrs_uav_managers/include/mrs_uav_managers/control_manager +
13.5%13.5%
+
13.5 %13 / 9618.5 %5 / 27
mrs_uav_managers/include/mrs_uav_managers/estimation_manager +
81.0%81.0%
+
81.0 %85 / 10586.7 %13 / 15
mrs_uav_managers/include/transform_manager +
47.1%47.1%
+
47.1 %186 / 39557.9 %11 / 19
mrs_uav_managers/src +
55.1%55.1%
+
55.1 %931 / 169072.6 %53 / 73
mrs_uav_managers/src/control_manager +
46.4%46.4%
+
46.4 %1723 / 371252.0 %64 / 123
mrs_uav_managers/src/control_manager/common +
27.9%27.9%
+
27.9 %157 / 56338.7 %12 / 31
mrs_uav_managers/src/estimation_manager +
63.8%63.8%
+
63.8 %391 / 61378.7 %37 / 47
mrs_uav_managers/src/estimation_manager/estimators +
60.7%60.7%
+
60.7 %82 / 135100.0 %13 / 13
mrs_uav_managers/src/transform_manager +
63.1%63.1%
+
63.1 %275 / 43676.9 %10 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/attitude_converter.h.func-sort-c.html b/mrs_lib/include/mrs_lib/attitude_converter.h.func-sort-c.html new file mode 100644 index 0000000000..eec8702f0d --- /dev/null +++ b/mrs_lib/include/mrs_lib/attitude_converter.h.func-sort-c.html @@ -0,0 +1,116 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/attitude_converter.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - attitude_converter.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:232785.2 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK7mrs_lib17AttitudeConverter18MathErrorException4whatEv0
_ZNK7mrs_lib17AttitudeConverter19SetHeadingException4whatEv0
_ZN7mrs_lib17AttitudeConverter3getILm0EEEDav1
_ZN7mrs_lib17AttitudeConverter3getILm1EEEDav1
_ZN7mrs_lib17AttitudeConverter3getILm2EEEDav1
_ZN7mrs_lib17AttitudeConverterC2IdEEN5Eigen9AngleAxisIT_EE1
_ZNK7mrs_lib17AttitudeConverter19GetHeadingException4whatEv1
_ZNK7mrs_lib17AttitudeConvertercvN5Eigen10QuaternionIT_Li0EEEIdEEv1
_ZNK7mrs_lib17AttitudeConvertercvN5Eigen9AngleAxisIT_EEIdEEv1
_ZNK7mrs_lib17AttitudeConverter24InvalidAttitudeException4whatEv2
_ZN7mrs_lib16Vector3ConverterC2ERKN3tf27Vector3E3007
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/attitude_converter.h.func.html b/mrs_lib/include/mrs_lib/attitude_converter.h.func.html new file mode 100644 index 0000000000..9e00d8d4fd --- /dev/null +++ b/mrs_lib/include/mrs_lib/attitude_converter.h.func.html @@ -0,0 +1,116 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/attitude_converter.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - attitude_converter.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:232785.2 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16Vector3ConverterC2ERKN3tf27Vector3E3007
_ZN7mrs_lib17AttitudeConverter3getILm0EEEDav1
_ZN7mrs_lib17AttitudeConverter3getILm1EEEDav1
_ZN7mrs_lib17AttitudeConverter3getILm2EEEDav1
_ZN7mrs_lib17AttitudeConverterC2IdEEN5Eigen9AngleAxisIT_EE1
_ZNK7mrs_lib17AttitudeConverter18MathErrorException4whatEv0
_ZNK7mrs_lib17AttitudeConverter19GetHeadingException4whatEv1
_ZNK7mrs_lib17AttitudeConverter19SetHeadingException4whatEv0
_ZNK7mrs_lib17AttitudeConverter24InvalidAttitudeException4whatEv2
_ZNK7mrs_lib17AttitudeConvertercvN5Eigen10QuaternionIT_Li0EEEIdEEv1
_ZNK7mrs_lib17AttitudeConvertercvN5Eigen9AngleAxisIT_EEIdEEv1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/attitude_converter.h.gcov.html b/mrs_lib/include/mrs_lib/attitude_converter.h.gcov.html new file mode 100644 index 0000000000..74499cd955 --- /dev/null +++ b/mrs_lib/include/mrs_lib/attitude_converter.h.gcov.html @@ -0,0 +1,609 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/attitude_converter.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - attitude_converter.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:232785.2 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: TomasFormat
+       2             : /**
+       3             :  * @file attitude_converter.h
+       4             :  *
+       5             :  * @brief Conversions between various representations of object attitude in 3D.
+       6             :  * Supports Quaternions, Euler angles, Angle-axis and Rotational matrices from tf, tf2, Eigen and geometry_msgs libraries.
+       7             :  * The default Euler angle notation is the extrinsic RPY.
+       8             :  *
+       9             :  * @author Tomas Baca
+      10             :  */
+      11             : 
+      12             : #ifndef ATTITUDE_CONVERTER_H
+      13             : #define ATTITUDE_CONVERTER_H
+      14             : 
+      15             : #include <vector>
+      16             : #include <cmath>
+      17             : #include <Eigen/Dense>
+      18             : #include <tuple>
+      19             : 
+      20             : #include <tf2_ros/transform_listener.h>
+      21             : #include <tf2_ros/buffer.h>
+      22             : #include <tf2_eigen/tf2_eigen.h>
+      23             : #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
+      24             : #include <tf/transform_datatypes.h>
+      25             : #include <tf_conversions/tf_eigen.h>
+      26             : 
+      27             : #include <mrs_lib/geometry/misc.h>
+      28             : 
+      29             : namespace mrs_lib
+      30             : {
+      31             : 
+      32             : // type of the object we are grasping
+      33             : typedef enum
+      34             : {
+      35             : 
+      36             :   RPY_INTRINSIC = 1,
+      37             :   RPY_EXTRINSIC = 2,
+      38             : 
+      39             : } RPY_convention_t;
+      40             : 
+      41             : /* class EulerAttitude //{ */
+      42             : 
+      43             : /**
+      44             :  * @brief A small class for storing the Euler angles.
+      45             :  */
+      46             : class EulerAttitude {
+      47             : public:
+      48             :   /**
+      49             :    * @brief A simple class for storing the Euler angles.
+      50             :    *
+      51             :    * @param roll
+      52             :    * @param pitch
+      53             :    * @param yaw
+      54             :    */
+      55             :   EulerAttitude(const double& roll, const double& pitch, const double& yaw);
+      56             : 
+      57             :   /**
+      58             :    * @brief get the roll angle
+      59             :    *
+      60             :    * @return roll
+      61             :    */
+      62             :   double roll(void) const;
+      63             : 
+      64             :   /**
+      65             :    * @brief get the pitch angle
+      66             :    *
+      67             :    * @return pitch
+      68             :    */
+      69             :   double pitch(void) const;
+      70             : 
+      71             :   /**
+      72             :    * @brief get the yaw angle
+      73             :    *
+      74             :    * @return yaw
+      75             :    */
+      76             :   double yaw(void) const;
+      77             : 
+      78             : private:
+      79             :   double roll_, pitch_, yaw_;
+      80             : };
+      81             : 
+      82             : //}
+      83             : 
+      84             : /* class Vector3Converter //{ */
+      85             : 
+      86             : /**
+      87             :  * @brief Converter of Vector3 representations. Instantiate it with any type of vector3 in constructor and convert it by assigning it to any other type of
+      88             :  * vector3 variable.
+      89             :  */
+      90             : class Vector3Converter {
+      91             : public:
+      92             :   /**
+      93             :    * @brief Constructor with tf2::Vector3
+      94             :    *
+      95             :    * @param vector3
+      96             :    */
+      97        3007 :   Vector3Converter(const tf2::Vector3& vector3) : vector3_(vector3){};
+      98             : 
+      99             :   /**
+     100             :    * @brief Constructor with Eigen::Vector3
+     101             :    *
+     102             :    * @param vector3
+     103             :    */
+     104             :   Vector3Converter(const Eigen::Vector3d& vector3);
+     105             : 
+     106             :   /**
+     107             :    * @brief Constructor with geometry_msgs::Vector3
+     108             :    *
+     109             :    * @param vector3
+     110             :    */
+     111             :   Vector3Converter(const geometry_msgs::Vector3& vector3);
+     112             : 
+     113             :   /**
+     114             :    * @brief Constructor with doubles: x, y, z
+     115             :    *
+     116             :    * @param x
+     117             :    * @param y
+     118             :    * @param z
+     119             :    */
+     120             :   Vector3Converter(const double& x, const double& y, const double& z);
+     121             : 
+     122             :   /**
+     123             :    * @brief typecast overloaded for tf2::Vector3
+     124             :    *
+     125             :    * @return vector3
+     126             :    */
+     127             :   operator tf2::Vector3() const;
+     128             : 
+     129             :   /**
+     130             :    * @brief typecast overloaded for Eigen::Vector3
+     131             :    *
+     132             :    * @return vector3
+     133             :    */
+     134             :   operator Eigen::Vector3d() const;
+     135             : 
+     136             :   /**
+     137             :    * @brief typecast overloaded for geometry_msgs::Vector3
+     138             :    *
+     139             :    * @return vector3
+     140             :    */
+     141             :   operator geometry_msgs::Vector3() const;
+     142             : 
+     143             : private:
+     144             :   tf2::Vector3 vector3_;
+     145             : };
+     146             : 
+     147             : //}
+     148             : 
+     149             : /**
+     150             :  * @brief The main convertor class. Instantiate with any type in constructor and get the value in any other type by assigning the instance to your variable,
+     151             :  * as: tf::Quaternion tf1_quaternion = AttitudeConverter(roll, pitch, yaw); All the default Euler angles are in the extrinsic RPY notation.
+     152             :  */
+     153             : class AttitudeConverter {
+     154             : public:
+     155             :   /* exceptions //{ */
+     156             : 
+     157             :   //! is thrown when calculating of heading is not possible due to atan2 exception
+     158             :   struct GetHeadingException : public std::exception
+     159             :   {
+     160           1 :     const char* what() const throw() {
+     161           1 :       return "AttitudeConverter: can not calculate the heading, the rotated x-axis is parallel to the world's z-axis";
+     162             :     }
+     163             :   };
+     164             : 
+     165             :   //! is thrown when math breaks
+     166             :   struct MathErrorException : public std::exception
+     167             :   {
+     168           0 :     const char* what() const throw() {
+     169           0 :       return "AttitudeConverter: math error";
+     170             :     }
+     171             :   };
+     172             : 
+     173             :   //! is thrown when the internal attitude becomes invalid
+     174             :   struct InvalidAttitudeException : public std::exception
+     175             :   {
+     176           2 :     const char* what() const throw() {
+     177           2 :       return "AttitudeConverter: invalid attitude, the input probably constains NaNs";
+     178             :     }
+     179             :   };
+     180             : 
+     181             :   //! is thrown when the Euler angle format is set wrongly
+     182             :   struct EulerFormatException : public std::exception
+     183             :   {
+     184             :     const char* what() const throw() {
+     185             :       return "AttitudeConverter: invalid Euler angle format";
+     186             :     }
+     187             :   };
+     188             : 
+     189             :   //! is thrown when the heading cannot be set to an existing attitude
+     190             :   struct SetHeadingException : public std::exception
+     191             :   {
+     192           0 :     const char* what() const throw() {
+     193           0 :       return "AttitudeConverter: cannot set the desired heading, the thrust vector's Z component is 0";
+     194             :     }
+     195             :   };
+     196             : 
+     197             :   //}
+     198             : 
+     199             :   /* constructors //{ */
+     200             : 
+     201             :   /**
+     202             :    * @brief Euler angles constructor
+     203             :    *
+     204             :    * @param roll
+     205             :    * @param pitch
+     206             :    * @param yaw
+     207             :    * @param format optional, Euler angle convention, {"extrinsic", "intrinsic"}, defaults to "extrinsic"
+     208             :    */
+     209        2020 :   AttitudeConverter(const double& roll, const double& pitch, const double& yaw, const RPY_convention_t& format = RPY_EXTRINSIC);
+     210             : 
+     211             :   /**
+     212             :    * @brief tf::Quaternion constructor
+     213             :    *
+     214             :    * @param quaternion tf::Quaternion quaternion
+     215             :    */
+     216             :   AttitudeConverter(const tf::Quaternion quaternion);
+     217             : 
+     218             :   /**
+     219             :    * @brief geometry_msgs::Quaternion constructor
+     220             :    *
+     221             :    * @param quaternion geometry_msgs::Quaternion quaternion
+     222             :    */
+     223             :   AttitudeConverter(const geometry_msgs::Quaternion quaternion);
+     224             : 
+     225             :   /**
+     226             :    * @brief mrs_lib::EulerAttitude constructor
+     227             :    *
+     228             :    * @param euler_attitude mrs_lib::EulerAttitude
+     229             :    */
+     230             :   AttitudeConverter(const mrs_lib::EulerAttitude& euler_attitude);
+     231             : 
+     232             :   /**
+     233             :    * @brief Eigen::Quaterniond constructor
+     234             :    *
+     235             :    * @param quaternion Eigen::Quaterniond quaternion
+     236             :    */
+     237             :   AttitudeConverter(const Eigen::Quaterniond quaternion);
+     238             : 
+     239             :   /**
+     240             :    * @brief Eigen::Matrix3d constructor
+     241             :    *
+     242             :    * @param matrix Eigen::Matrix3d rotational matrix
+     243             :    */
+     244             :   AttitudeConverter(const Eigen::Matrix3d matrix);
+     245             : 
+     246             :   /**
+     247             :    * @brief Eigen::AngleAxis constructor
+     248             :    *
+     249             :    * @tparam T angle-axis base type
+     250             :    * @param angle_axis Eigen::AngleAxis
+     251             :    */
+     252             :   template <class T>
+     253           1 :   AttitudeConverter(const Eigen::AngleAxis<T> angle_axis) {
+     254           1 :     double       angle = angle_axis.angle();
+     255           1 :     tf2::Vector3 axis(angle_axis.axis()[0], angle_axis.axis()[1], angle_axis.axis()[2]);
+     256             : 
+     257           1 :     tf2_quaternion_.setRotation(axis, angle);
+     258           1 :   }
+     259             : 
+     260             :   /**
+     261             :    * @brief tf2::Quaternion constructor
+     262             :    *
+     263             :    * @param quaternion tf2::Quaternion
+     264             :    */
+     265             :   AttitudeConverter(const tf2::Quaternion quaternion);
+     266             : 
+     267             :   /**
+     268             :    * @brief tf2::Matrix3x3 constructor
+     269             :    *
+     270             :    * @param quaternion tf2::Matrix3x3
+     271             :    */
+     272             :   AttitudeConverter(const tf2::Matrix3x3 matrix);
+     273             : 
+     274             :   //}
+     275             : 
+     276             :   /* operators //{ */
+     277             : 
+     278             :   /**
+     279             :    * @brief typecast to tf2::Quaternion
+     280             :    *
+     281             :    * @return orientation in tf2::Quaternion
+     282             :    */
+     283             :   operator tf2::Quaternion() const;
+     284             : 
+     285             :   /**
+     286             :    * @brief typecast to tf::Quaternion
+     287             :    *
+     288             :    * @return orientation in tf::Quaternion
+     289             :    */
+     290             :   operator tf::Quaternion() const;
+     291             : 
+     292             :   /**
+     293             :    * @brief typecast to geometry_msgs::Quaternion
+     294             :    *
+     295             :    * @return orientation in geometry_msgs::Quaternion
+     296             :    */
+     297             :   operator geometry_msgs::Quaternion() const;
+     298             : 
+     299             :   /**
+     300             :    * @brief typecast to EulerAttitude
+     301             :    *
+     302             :    * @return orientation in EulerAttitude
+     303             :    */
+     304             :   operator EulerAttitude() const;
+     305             : 
+     306             :   /**
+     307             :    * @brief typecast to Eigen::AngleAxis
+     308             :    *
+     309             :    * @tparam T angle-axis base type
+     310             :    *
+     311             :    * @return orientation in EulerAttitude
+     312             :    */
+     313             :   template <class T>
+     314           1 :   operator Eigen::AngleAxis<T>() const {
+     315             : 
+     316           1 :     double          angle = tf2_quaternion_.getAngle();
+     317           1 :     Eigen::Vector3d axis(tf2_quaternion_.getAxis()[0], tf2_quaternion_.getAxis()[1], tf2_quaternion_.getAxis()[2]);
+     318             : 
+     319           1 :     Eigen::AngleAxis<T> angle_axis(angle, axis);
+     320             : 
+     321           2 :     return angle_axis;
+     322             :   }
+     323             : 
+     324             : 
+     325             :   /**
+     326             :    * @brief typecast to EulerAttitude Eigen::Quaternion
+     327             :    *
+     328             :    * @tparam T quaternion base type
+     329             :    *
+     330             :    * @return orientation in Eigen::Quaternion
+     331             :    */
+     332             :   template <class T>
+     333           1 :   operator Eigen::Quaternion<T>() const {
+     334             : 
+     335           1 :     return Eigen::Quaternion<T>(tf2_quaternion_.w(), tf2_quaternion_.x(), tf2_quaternion_.y(), tf2_quaternion_.z());
+     336             :   }
+     337             : 
+     338             :   operator Eigen::Matrix3d() const;
+     339             : 
+     340             :   /**
+     341             :    * @brief typecase to tuple of Euler angles in extrinsic RPY
+     342             :    *
+     343             :    * @return std::tuple of extrinsic RPY
+     344             :    */
+     345             :   operator std::tuple<double&, double&, double&>();
+     346             : 
+     347             :   /**
+     348             :    * @brief typecase to tf2::Matrix3x3
+     349             :    *
+     350             :    * @return tf2::Matrix3x3 rotational matrix
+     351             :    */
+     352             :   operator tf2::Matrix3x3() const;
+     353             : 
+     354             :   /**
+     355             :    * @brief typecase to tf2::Transform
+     356             :    *
+     357             :    * @return tf2::Transform
+     358             :    */
+     359             :   operator tf2::Transform() const;
+     360             : 
+     361             :   //}
+     362             : 
+     363             :   /* getters //{ */
+     364             : 
+     365             :   /**
+     366             :    * @brief get the roll angle
+     367             :    *
+     368             :    * @return roll
+     369             :    */
+     370             :   double getRoll(void);
+     371             : 
+     372             :   /**
+     373             :    * @brief get the pitch angle
+     374             :    *
+     375             :    * @return pitch
+     376             :    */
+     377             :   double getPitch(void);
+     378             : 
+     379             :   /**
+     380             :    * @brief get the yaw angle
+     381             :    *
+     382             :    * @return yaw
+     383             :    */
+     384             :   double getYaw(void);
+     385             : 
+     386             :   /**
+     387             :    * @brief get the angle of the rotated x-axis in the original XY plane, a.k.a
+     388             :    *
+     389             :    * @return heading
+     390             :    */
+     391             :   double getHeading(void);
+     392             : 
+     393             :   /**
+     394             :    * @brief get heading rate base on the orientation and body-based attitude rate
+     395             :    *
+     396             :    * @param attitude_rate in the body frame
+     397             :    *
+     398             :    * @return heading rate in the world
+     399             :    */
+     400             :   double getHeadingRate(const Vector3Converter& attitude_rate);
+     401             : 
+     402             :   /**
+     403             :    * @brief get the intrinsic yaw rate from a heading rate
+     404             :    *
+     405             :    * @param heading_rate
+     406             :    *
+     407             :    * @return intrinsic yaw rate
+     408             :    */
+     409             :   double getYawRateIntrinsic(const double& heading_rate);
+     410             : 
+     411             :   /**
+     412             :    * @brief get a unit vector pointing in the X direction
+     413             :    *
+     414             :    * @return the vector
+     415             :    */
+     416             :   Vector3Converter getVectorX(void);
+     417             : 
+     418             :   /**
+     419             :    * @brief get a unit vector pointing in the Y direction
+     420             :    *
+     421             :    * @return the vector
+     422             :    */
+     423             :   Vector3Converter getVectorY(void);
+     424             : 
+     425             :   /**
+     426             :    * @brief get a unit vector pointing in the Z direction
+     427             :    *
+     428             :    * @return the vector
+     429             :    */
+     430             :   Vector3Converter getVectorZ(void);
+     431             : 
+     432             :   /**
+     433             :    * @brief get the Roll, Pitch, Yaw angles in the Intrinsic convention
+     434             :    *
+     435             :    * @return RPY
+     436             :    */
+     437             :   std::tuple<double, double, double> getIntrinsicRPY();
+     438             : 
+     439             :   /**
+     440             :    * @brief get the Roll, Pitch, Yaw angles in the Extrinsic convention. The same as the default AttitudeConverter assignment.
+     441             :    *
+     442             :    * @return RPY
+     443             :    */
+     444             :   std::tuple<double, double, double> getExtrinsicRPY();
+     445             : 
+     446             :   //}
+     447             : 
+     448             :   /* setters //{ */
+     449             : 
+     450             :   /**
+     451             :    * @brief Updates the heading of the current orientation by updating the intrinsic yaw
+     452             :    *
+     453             :    * @param new heading
+     454             :    *
+     455             :    * @return the orientation
+     456             :    */
+     457             :   AttitudeConverter setHeading(const double& heading);
+     458             : 
+     459             :   /**
+     460             :    * @brief Updates the extrinsic yaw of the current orientation.
+     461             :    *
+     462             :    * @param new yaw
+     463             :    *
+     464             :    * @return the orientation
+     465             :    */
+     466             :   AttitudeConverter setYaw(const double& new_yaw);
+     467             : 
+     468             :   //}
+     469             : 
+     470             :   template <std::size_t I>
+     471             :   constexpr auto get();
+     472             : 
+     473             : private:
+     474             :   /**
+     475             :    * @brief Internal representation of the attitude
+     476             :    */
+     477             :   tf2::Quaternion tf2_quaternion_;
+     478             : 
+     479             :   /**
+     480             :    * @brief convert the internal quaternion representation to internally-stored RPY
+     481             :    */
+     482             :   void calculateRPY(void);
+     483             : 
+     484             :   /**
+     485             :    * @brief throws exception when the internal attitude is invalid
+     486             :    */
+     487             :   void validateOrientation(void);
+     488             : 
+     489             :   /**
+     490             :    * @brief Internal representation in RPY. is used only when converting to RPY.
+     491             :    */
+     492             :   double roll_, pitch_, yaw_;
+     493             :   bool   got_rpy_ = false;
+     494             : };
+     495             : 
+     496             : 
+     497             : template <std::size_t I>
+     498           3 : constexpr auto AttitudeConverter::get() {
+     499             : 
+     500           3 :   calculateRPY();
+     501             : 
+     502             :   // call compilation error if I > 2
+     503             :   static_assert(I <= 2);
+     504             : 
+     505             :   // get the RPY components based on the index in the tuple
+     506             :   if constexpr (I == 0) {
+     507           1 :     return static_cast<double>(roll_);
+     508             :   } else if constexpr (I == 1) {
+     509           1 :     return static_cast<double>(pitch_);
+     510             :   } else if constexpr (I == 2) {
+     511           1 :     return static_cast<double>(yaw_);
+     512             :   }
+     513             : }
+     514             : 
+     515             : }  // namespace mrs_lib
+     516             : 
+     517             : template <>
+     518             : struct std::tuple_size<mrs_lib::AttitudeConverter>
+     519             : { static constexpr int value = 3; };
+     520             : 
+     521             : template <>
+     522             : struct std::tuple_element<0, mrs_lib::AttitudeConverter>
+     523             : { using type = double; };
+     524             : 
+     525             : template <>
+     526             : struct std::tuple_element<1, mrs_lib::AttitudeConverter>
+     527             : { using type = double; };
+     528             : 
+     529             : template <>
+     530             : struct std::tuple_element<2, mrs_lib::AttitudeConverter>
+     531             : { using type = double; };
+     532             : 
+     533             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/cyclic.h.func-sort-c.html b/mrs_lib/include/mrs_lib/geometry/cyclic.h.func-sort-c.html new file mode 100644 index 0000000000..9bb4ce6086 --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/cyclic.h.func-sort-c.html @@ -0,0 +1,540 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry/cyclic.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometry - cyclic.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:598767.8 %
Date:2023-11-29 14:09:54Functions:4411737.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE15interpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE15interpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4distES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4distEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE6interpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2ERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEaSEOS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEmIERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEpLERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE15interpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE15interpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE6interpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE15interpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE15interpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4distES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4distEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE6interpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2ERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEaSEOS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEmIERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEpLERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEaSEOS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEmIERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEpLERKS3_0
_ZNK7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE5valueEv0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7convertINS0_7radiansEEET_RKS3_1
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEmIERKS3_1
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEpLERKS3_1
_ZNK7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7convertINS0_7radiansEEET_v1
_ZN7mrs_lib8geometrygtIdNS0_7radiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZN7mrs_lib8geometrygtIdNS0_8sradiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZN7mrs_lib8geometryltIdNS0_7radiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZN7mrs_lib8geometryltIdNS0_8sradiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZNK7mrs_lib8geometry6cyclicIdNS0_7degreesEE5valueEv4
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEaSEOS3_6
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4diffES3_S3_10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4diffEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE6unwrapEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4distEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE6unwrapEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4diffES3_S3_10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4diffEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE6unwrapEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE15interpUnwrappedES3_S3_d10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE15interpUnwrappedEddd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4distEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE6interpEddd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE6unwrapEdd10000
_ZNK7mrs_lib8geometry6cyclicIdNS0_7radiansEE5valueEv10002
_ZN7mrs_lib8geometryplERKNS0_6cyclicIdNS0_7radiansEEES5_10004
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4distES3_S3_10008
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4distES3_S3_10008
_ZN7mrs_lib8geometrymiERKNS0_6cyclicIdNS0_7radiansEEES5_10009
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2Ed20000
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4diffEdd20001
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2Ed20005
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4diffEdd20063
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4wrapEd30000
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4wrapEd30005
_ZN7mrs_lib8geometryplERKNS0_6cyclicIdNS0_8sradiansEEES5_40000
_ZNK7mrs_lib8geometry6cyclicIdNS0_8sradiansEE5valueEv40002
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4diffES3_S3_40018
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2ERKS3_40024
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2ERKS3_40042
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4diffES3_S3_40071
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2Ed110035
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4wrapEd130040
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2Ed180139
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4wrapEd240139
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/cyclic.h.func.html b/mrs_lib/include/mrs_lib/geometry/cyclic.h.func.html new file mode 100644 index 0000000000..cfe0ba2b5e --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/cyclic.h.func.html @@ -0,0 +1,540 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry/cyclic.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometry - cyclic.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:598767.8 %
Date:2023-11-29 14:09:54Functions:4411737.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE15interpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE15interpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4diffES3_S3_10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4diffEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4distES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4distEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE4wrapEd30005
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE6interpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE6unwrapEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7convertINS0_7radiansEEET_RKS3_1
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2ERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2Ed20005
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEaSEOS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEmIERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7degreesEEpLERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE15interpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE15interpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4diffES3_S3_40018
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4diffEdd20001
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4distES3_S3_10008
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4distEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE4wrapEd130040
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE6interpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE6unwrapEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2ERKS3_40042
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2Ed110035
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEaSEOS3_6
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEmIERKS3_1
_ZN7mrs_lib8geometry6cyclicIdNS0_7radiansEEpLERKS3_1
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE15interpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE15interpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4diffES3_S3_10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4diffEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4distES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4distEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE4wrapEd30000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE6interpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE6unwrapEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2ERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2Ed20000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEaSEOS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEmIERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sdegreesEEpLERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE15interpUnwrappedES3_S3_d10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE15interpUnwrappedEddd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE16pinterpUnwrappedES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE16pinterpUnwrappedEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4diffES3_S3_40071
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4diffEdd20063
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4distES3_S3_10008
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4distEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE4wrapEd240139
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE5pdistES3_S3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE5pdistEdd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE6interpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE6interpEddd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE6unwrapEdd10000
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7inRangeEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7pinterpES3_S3_d0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7pinterpEddd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2ERKS2_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2ERKS3_40024
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2Ed180139
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEC2Ev0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEaSEOS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEaSERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEaSEd0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEmIERKS3_0
_ZN7mrs_lib8geometry6cyclicIdNS0_8sradiansEEpLERKS3_0
_ZN7mrs_lib8geometrygtIdNS0_7radiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZN7mrs_lib8geometrygtIdNS0_8sradiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZN7mrs_lib8geometryltIdNS0_7radiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZN7mrs_lib8geometryltIdNS0_8sradiansEEEbRKNS0_6cyclicIT_T0_EES8_2
_ZN7mrs_lib8geometrymiERKNS0_6cyclicIdNS0_7radiansEEES5_10009
_ZN7mrs_lib8geometryplERKNS0_6cyclicIdNS0_7radiansEEES5_10004
_ZN7mrs_lib8geometryplERKNS0_6cyclicIdNS0_8sradiansEEES5_40000
_ZNK7mrs_lib8geometry6cyclicIdNS0_7degreesEE5valueEv4
_ZNK7mrs_lib8geometry6cyclicIdNS0_7radiansEE5valueEv10002
_ZNK7mrs_lib8geometry6cyclicIdNS0_8sdegreesEE5valueEv0
_ZNK7mrs_lib8geometry6cyclicIdNS0_8sradiansEE5valueEv40002
_ZNK7mrs_lib8geometry6cyclicIdNS0_8sradiansEE7convertINS0_7radiansEEET_v1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/cyclic.h.gcov.html b/mrs_lib/include/mrs_lib/geometry/cyclic.h.gcov.html new file mode 100644 index 0000000000..981a1d9d95 --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/cyclic.h.gcov.html @@ -0,0 +1,604 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry/cyclic.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometry - cyclic.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:598767.8 %
Date:2023-11-29 14:09:54Functions:4411737.6 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : /**  \file
+       3             :      \brief Defines the cyclic class for calculations with cyclic quantities.
+       4             :      \author Matouš Vrba - vrbamato@fel.cvut.cz
+       5             :  */
+       6             : 
+       7             : #ifndef CYCLIC_H
+       8             : #define CYCLIC_H
+       9             : 
+      10             : #include <cmath>
+      11             : #include <ostream>
+      12             : 
+      13             : namespace mrs_lib
+      14             : {
+      15             :   namespace geometry
+      16             :   {
+      17             :     /**
+      18             :      * \brief Implementation of the a general cyclic value (such as angles in radians/degrees etc).
+      19             :      *
+      20             :      * This class implements a periodical value with a period of \f$ r \in {\rm I\!R} \f$ so that a general number \f$ v \in {\rm I\!R} \f$ represents the same
+      21             :      * value as \f$ v + kr,~k \in {\rm I\!N} \f$. For the purposes of calculations in this class, \f$ v \f$ is confined to a half-open interval \f$ v \in
+      22             :      * [~m,~s~[ \f$, where \f$ m \f$ is the minimum of this interval and \f$ s \f$ is its supremum, and \f$ s = m + r \f$ holds. This approach enables
+      23             :      * representing \f$ v \f$ in different intervals on the real numbers axis; eg. angle in radians may be represented within the interval \f$ v \in
+      24             :      * [~-\pi,~\pi~[ \f$ or \f$ v \in [~0,~2\pi~[ \f$, according to the needs of the specific application. The period \f$ r \f$ is called \p range for the
+      25             :      * purposes of this class, as it represents range of the interval of valid ("wrapped") values of \f$ v \f$.
+      26             :      *
+      27             :      * This class may be used as an object or its static methods may be used on regular floating-point types, avoiding any object-related overheads (see
+      28             :      * example). Specializations for the most common cyclic values are provided and a new specialization may be easily created simply by inheriting from this
+      29             :      * class and specifying a different minimum and supremum values.
+      30             :      *
+      31             :      * Implementation inspired by: https://www.codeproject.com/Articles/190833/Circular-Values-Math-and-Statistics-with-Cplusplus
+      32             :      *
+      33             :      * \parblock
+      34             :      * \note For a better intuitive understanding of the used functions, the term **walk** is sometimes used in the function explanations.
+      35             :      * You can imagine walking along the circle from one angle to another (represented by the circular quantities).
+      36             :      * The walk may be the shortest - then you're walking in such a manner that you reach the other point in the least of steps.
+      37             :      * The walk may also be oriented - then you're walking in a specific direction (ie. according to the increasing/decreasing angle).
+      38             :      * \endparblock
+      39             :      *
+      40             :      * \parblock
+      41             :      * \note The terms **circular quantity** and **value** are used in the function explanations.
+      42             :      * A circular quantity is eg. an angle and the same quantity may be represented using different values: the same angle is represented by the values of 100
+      43             :      * degrees and 460 degrees. \endparblock
+      44             :      *
+      45             :      * \tparam flt floating data type to be used by this class.
+      46             :      */
+      47             :     template <typename flt, class spec>
+      48             :     struct cyclic
+      49             :     {
+      50             :       /*!
+      51             :        * \brief Default constructor.
+      52             :        *
+      53             :        * Sets the value to the minimum.
+      54             :        */
+      55           0 :       cyclic() : val(minimum){};
+      56             :       /*!
+      57             :        * \brief Constructor overload.
+      58             :        *
+      59             :        * \param val initialization value (will be wrapped).
+      60             :        */
+      61      330179 :       cyclic(const flt val) : val(wrap(val)){};
+      62             :       /*!
+      63             :        * \brief Copy constructor.
+      64             :        *
+      65             :        * \param val initialization value.
+      66             :        */
+      67       80066 :       cyclic(const cyclic& other) : val(other.val){};
+      68             :       /*!
+      69             :        * \brief Copy constructor.
+      70             :        *
+      71             :        * \param val initialization value.
+      72             :        */
+      73           0 :       cyclic(const spec& other) : val(other.val){};
+      74             : 
+      75             :       /*!
+      76             :        * \brief Getter for \p val.
+      77             :        *
+      78             :        * \return the value.
+      79             :        */
+      80       50008 :       flt value() const
+      81             :       {
+      82       50008 :         return val;
+      83             :       };
+      84             : 
+      85             :       static constexpr flt minimum = spec::minimum;   /*!< \brief Minimum of the valid interval of wrapped values \f$ m \f$ */
+      86             :       static constexpr flt supremum = spec::supremum; /*!< \brief Supremum of the valid interval of wrapped values \f$ s \f$ */
+      87             :       static constexpr flt range =
+      88             :           supremum - minimum; /*!< \brief Range of the valid interval of wrapped values \f$ r \f$ (also the period of the cyclic quantity). */
+      89             :       static constexpr flt half_range =
+      90             :           range / flt(2); /*!< \brief Half of the range of the valid interval of wrapped values \f$ r/2 \f$ (used for some calculations). */
+      91             : 
+      92             :       /* static_assert((supremum > minimum), "cyclic value: Range not valid"); */
+      93             : 
+      94             :       /*!
+      95             :        * \brief Checks if \p val is within the valid interval of wrapped values.
+      96             :        *
+      97             :        * \param val the value to be checked.
+      98             :        * \returns   true if \p val is within the valid interval of wrapped values.
+      99             :        */
+     100           0 :       static bool inRange(const flt val)
+     101             :       {
+     102           0 :         return val >= minimum && val < supremum;
+     103             :       }
+     104             : 
+     105             :       /*!
+     106             :        * \brief Returns \p val, converted to the valid interval of values.
+     107             :        *
+     108             :        * The wrapped value represents the same quantity as the parameter (ie. \f$ v' = v + kr \f$, where \f$ v \f$ is the parameter and \f$ v' \f$ is the
+     109             :        * returned value).
+     110             :        *
+     111             :        * \param val the value to be wrapped.
+     112             :        * \returns   \p val wrapped to the valid interval of values.
+     113             :        */
+     114      430184 :       static flt wrap(const flt val)
+     115             :       {
+     116             :         // these few ifs should cover most cases, improving speed and precision
+     117      430184 :         if (val >= minimum)
+     118             :         {
+     119      259967 :           if (val < supremum)  // value is actually in range and doesn't need to be wrapped
+     120       86381 :             return val;
+     121      173586 :           else if (val < supremum + range)
+     122       11083 :             return val - range;  // to avoid unnecessary costly fmod operation for this case (assumed to be significantly more common than the general case)
+     123             :         } else
+     124             :         {
+     125      170217 :           if (val >= minimum - range)
+     126        6232 :             return val + range;  // to avoid unnecessary costly fmod operation for this case (assumed to be significantly more common than the general case)
+     127             :         }
+     128             : 
+     129             :         // general case
+     130      326488 :         const flt rem = std::fmod(val - minimum, range);
+     131      326488 :         const flt wrapped = rem + minimum + std::signbit(rem) * range;
+     132      326488 :         return wrapped;
+     133             :       }
+     134             : 
+     135             :       /*!
+     136             :        * \brief Returns value of the parameter \p what modified so that there is no "jump" between \p from and \t what.
+     137             :        *
+     138             :        * The circular difference between the two input quantities is preserved, but the returned value is modified if necessary so that the linear distance
+     139             :        * between the values is the smallest. This is useful whenever you need to preserve linear continuity of consecutive values, eg. when commanding a
+     140             :        * multi-rotational servo motor or when using a simple linear Kalman filter to estimate circular quantities.
+     141             :        *
+     142             :        * An example of inputs and outputs if \f$ m = 0,~s=360 \f$:
+     143             :        *  \p what | \p from  | \p return
+     144             :        *  ------- | -------- | ---------
+     145             :        *    20    |    10    |   20
+     146             :        *    20    |    350   |   380
+     147             :        *    0     |    350   |   360
+     148             :        *    200   |    10    |  -160
+     149             :        *
+     150             :        * \param what   the value to be unwrapped.
+     151             :        * \param from   the previous value from which the unwrapped value of \p what should have the same circular difference and minimal linear distance.
+     152             :        * \returns      the unwrapped value of \p what.
+     153             :        *
+     154             :        * \warning Note that the returned value may be outside the valid interval of wrapped values, specified by the \p minimum and \p supremum parameters of
+     155             :        * this class.
+     156             :        */
+     157       40000 :       static flt unwrap(const flt what, const flt from)
+     158             :       {
+     159       40000 :         return from + diff(what, from);
+     160             :       }
+     161             : 
+     162             :       /*!
+     163             :        * \brief Returns length of the shortest walk in the positive direction from the first parameter to the second one.
+     164             :        *
+     165             :        * \param from   the positive walk starts at this value.
+     166             :        * \param to     the positive walk ends at this value.
+     167             :        * \returns      length of the shortest positive walk from the first parameter to the second one.
+     168             :        *
+     169             :        * \note The returned value is not necessarily the shortest distance between the two circular quantities (see the dist() function for that).
+     170             :        */
+     171           0 :       static flt pdist(const flt from, const flt to)
+     172             :       {
+     173           0 :         return pdist(cyclic(from), cyclic(to));
+     174             :       }
+     175             : 
+     176           0 :       static flt pdist(const cyclic from, const cyclic to)
+     177             :       {
+     178           0 :         const flt tmp = to.val - from.val;
+     179           0 :         const flt dist = tmp + std::signbit(tmp) * range;
+     180           0 :         return dist;
+     181             :       }
+     182             : 
+     183             :       /*!
+     184             :        * \brief Returns the difference between the two circular values.
+     185             :        *
+     186             :        * The difference may also be interpreted as length of the shortest walk between the two values, with a sign according to the direction of the shortest
+     187             :        * walk.
+     188             :        *
+     189             :        * \param minuend      the \p subtrahend will be subtracted from this value.
+     190             :        * \param subtrahend   this value will be subtracted from the \p minuend.
+     191             :        * \returns            the difference of the two circular quantities.
+     192             :        */
+     193       60064 :       static flt diff(const flt minuend, const flt subtrahend)
+     194             :       {
+     195       60064 :         return diff(cyclic(minuend), cyclic(subtrahend));
+     196             :       }
+     197             : 
+     198      100089 :       static flt diff(const cyclic minuend, const cyclic subtrahend)
+     199             :       {
+     200      100089 :         const flt d = minuend.val - subtrahend.val;
+     201      100089 :         if (d < -half_range)
+     202       12252 :           return d + range;
+     203       87837 :         if (d >= half_range)
+     204       12848 :           return d - range;
+     205       74989 :         return d;
+     206             :       }
+     207             : 
+     208             :       /*!
+     209             :        * \brief Returns the distance between the two circular values.
+     210             :        *
+     211             :        * The distance may also be interpreted as length of the shortest walk between the two values.
+     212             :        *
+     213             :        * \param from  the first circular quantity.
+     214             :        * \param to    the second circular quantity.
+     215             :        * \returns     distance of the two circular quantities.
+     216             :        *
+     217             :        * \note The order of the parameters doesn't matter.
+     218             :        */
+     219       20000 :       static flt dist(const flt from, const flt to)
+     220             :       {
+     221       20000 :         return dist(cyclic(from), cyclic(to));
+     222             :       }
+     223             : 
+     224       20016 :       static flt dist(const cyclic from, const cyclic to)
+     225             :       {
+     226       20016 :         return std::abs(diff(from, to));
+     227             :       }
+     228             : 
+     229             :       /*!
+     230             :        * \brief Interpolation between two circular quantities without wrapping of the result.
+     231             :        *
+     232             :        * This function doesn't wrap the returned value.
+     233             :        *
+     234             :        * \param from  the first circular quantity.
+     235             :        * \param to    the second circular quantity.
+     236             :        * \param coeff the interpolation coefficient.
+     237             :        * \returns     interpolation of the two circular quantities using the coefficient.
+     238             :        *
+     239             :        * \warning Note that the returned value may be outside the valid interval of wrapped values, specified by the \p minimum and \p supremum parameters of
+     240             :        * this class.
+     241             :        */
+     242       10000 :       static flt interpUnwrapped(const flt from, const flt to, const flt coeff)
+     243             :       {
+     244       10000 :         return interpUnwrapped(cyclic(from), cyclic(to), coeff);
+     245             :       }
+     246             : 
+     247       10000 :       static flt interpUnwrapped(const cyclic from, const cyclic to, const flt coeff)
+     248             :       {
+     249       10000 :         const flt dang = diff(to, from);
+     250       10000 :         const flt intp = from.val + coeff * dang;
+     251       10000 :         return intp;
+     252             :       }
+     253             : 
+     254             :       /*!
+     255             :        * \brief Interpolation between two circular quantities.
+     256             :        *
+     257             :        * This function wraps the returned value so that it is in the interval of valid values.
+     258             :        *
+     259             :        * \param from  the first circular quantity.
+     260             :        * \param to    the second circular quantity.
+     261             :        * \param coeff the interpolation coefficient.
+     262             :        * \returns     interpolation of the two circular quantities using the coefficient, wrapped to the interval of valid values.
+     263             :        */
+     264       10000 :       static flt interp(const flt from, const flt to, const flt coeff)
+     265             :       {
+     266       10000 :         return wrap(interpUnwrapped(from, to, coeff));
+     267             :       }
+     268             : 
+     269           0 :       static flt interp(const cyclic from, const cyclic to, const flt coeff)
+     270             :       {
+     271           0 :         return wrap(interpUnwrapped(from, to, coeff));
+     272             :       }
+     273             : 
+     274             :       /*!
+     275             :        * \brief Interpolation between two circular quantities in the positive direction without wrapping of the result.
+     276             :        *
+     277             :        * Interpolates the two values in the positive direction from the first parameter to the second by the coefficient.
+     278             :        * This function doesn't wrap the returned value.
+     279             :        *
+     280             :        * \param from  the first circular quantity.
+     281             :        * \param to    the second circular quantity.
+     282             :        * \param coeff the interpolation coefficient.
+     283             :        * \returns     interpolation of the two circular quantities using the coefficient.
+     284             :        *
+     285             :        * \warning Note that the returned value may be outside the valid interval of wrapped values, specified by the \p minimum and \p supremum parameters of
+     286             :        * this class.
+     287             :        */
+     288           0 :       static flt pinterpUnwrapped(const flt from, const flt to, const flt coeff)
+     289             :       {
+     290           0 :         return pinterpUnwrapped(cyclic(from), cyclic(to), coeff);
+     291             :       }
+     292             : 
+     293           0 :       static flt pinterpUnwrapped(const cyclic from, const cyclic to, const flt coeff)
+     294             :       {
+     295           0 :         const flt dang = pdist(to, from);
+     296           0 :         const flt intp = from.val + coeff * dang;
+     297           0 :         return intp;
+     298             :       }
+     299             : 
+     300             :       /*!
+     301             :        * \brief Interpolation between two circular quantities in the positive direction.
+     302             :        *
+     303             :        * Interpolates the two values in the positive direction from the first parameter to the second by the coefficient.
+     304             :        * This function wraps the returned value so that it is in the interval of valid values.
+     305             :        *
+     306             :        * \param from  the first circular quantity.
+     307             :        * \param to    the second circular quantity.
+     308             :        * \param coeff the interpolation coefficient.
+     309             :        * \returns     interpolation of the two circular quantities using the coefficient, wrapped to the interval of valid values.
+     310             :        */
+     311           0 :       static flt pinterp(const flt from, const flt to, const flt coeff)
+     312             :       {
+     313           0 :         return pinterpUnwrapped(cyclic(from), cyclic(to), coeff);
+     314             :       }
+     315             : 
+     316           0 :       static flt pinterp(const cyclic from, const cyclic to, const flt coeff)
+     317             :       {
+     318           0 :         return wrap(pinterpUnwrapped(from, to, coeff));
+     319             :       }
+     320             : 
+     321             :       /*!
+     322             :        * \brief Conversion between two different circular quantities.
+     323             :        *
+     324             :        * This function converts its parameter, interpreted as the circular quantity, represented by this class, to the \p other_t type of circular quantity.
+     325             :        *
+     326             :        * \param what       the circular quantity to be converted.
+     327             :        * \returns          the circular quantity converted to the range of \p other_t.
+     328             :        * \tparam other_t   type of the circular quantity to be converted to.
+     329             :        *
+     330             :        * \warning For the purposes of this function, it is assumed that the range of one type corresponds to the whole range of the other type and zeros of both
+     331             :        * types correspond to each other (such as when converting eg. degrees to radians).
+     332             :        */
+     333             :       template <class other_t>
+     334           1 :       static other_t convert(const cyclic& what)
+     335             :       {
+     336           1 :         return other_t(what.val / range * other_t::range);
+     337             :       }
+     338             : 
+     339             :       /*!
+     340             :        * \brief Conversion between two different circular quantities.
+     341             :        *
+     342             :        * This method returns the circular quantity, represented by this object, converted to the \p other_t type of circular quantity.
+     343             :        *
+     344             :        * \returns          the circular quantity converted to the range of \p other_t.
+     345             :        * \tparam other_t   type of the circular quantity to be converted to.
+     346             :        *
+     347             :        * \warning For the purposes of this function, it is assumed that the range of one type corresponds to the whole range of the other type and zeros of both
+     348             :        * types correspond to each other (such as when converting eg. degrees to radians).
+     349             :        */
+     350             :       template <class other_t>
+     351           1 :       other_t convert() const
+     352             :       {
+     353           1 :         return other_t(val / range * other_t::range);
+     354             :       }
+     355             : 
+     356             :       // | ------------------------ Operators ----------------------- |
+     357             :       /*!
+     358             :        * \brief Assignment operator.
+     359             :        *
+     360             :        * \param nval value to be assigned (will be wrapped).
+     361             :        * \return     reference to self.
+     362             :        */
+     363           0 :       cyclic& operator=(const flt nval)
+     364             :       {
+     365           0 :         val = wrap(nval);
+     366           0 :         return *this;
+     367             :       };
+     368             :       /*!
+     369             :        * \brief Assignment operator.
+     370             :        *
+     371             :        * \param other value to be assigned.
+     372             :        * \return      reference to self.
+     373             :        */
+     374           0 :       cyclic& operator=(const cyclic& other)
+     375             :       {
+     376           0 :         val = other.val;
+     377           0 :         return *this;
+     378             :       };
+     379             :       /*!
+     380             :        * \brief Move operator.
+     381             :        *
+     382             :        * \param other value to be assigned.
+     383             :        * \return      reference to self.
+     384             :        */
+     385           6 :       cyclic& operator=(cyclic&& other)
+     386             :       {
+     387           6 :         val = other.val;
+     388           6 :         return *this;
+     389             :       };
+     390             : 
+     391             :       /*!
+     392             :        * \brief Addition compound operator.
+     393             :        *
+     394             :        * \param other value to be added.
+     395             :        * \return      reference to self.
+     396             :        */
+     397           1 :       cyclic& operator+=(const cyclic& other)
+     398             :       {
+     399           1 :         val = wrap(val + other.val);
+     400           1 :         return *this;
+     401             :       };
+     402             : 
+     403             :       /*!
+     404             :        * \brief Subtraction compound operator.
+     405             :        *
+     406             :        * \param other value to be subtracted.
+     407             :        * \return      reference to self.
+     408             :        */
+     409           1 :       cyclic& operator-=(const cyclic& other)
+     410             :       {
+     411           1 :         val = diff(val, other.val);
+     412           1 :         return *this;
+     413             :       };
+     414             : 
+     415             :       /*!
+     416             :        * \brief Addition operator.
+     417             :        *
+     418             :        * \param lhs left-hand-side.
+     419             :        * \param rhs right-hand-side.
+     420             :        * \return    the result of adding the two angles.
+     421             :        */
+     422       50004 :       friend spec operator+(const cyclic& lhs, const cyclic& rhs)
+     423             :       {
+     424       50004 :         return wrap(lhs.val + rhs.val);
+     425             :       }
+     426             : 
+     427             :       /*!
+     428             :        * \brief Subtraction operator (uses the diff() method).
+     429             :        *
+     430             :        * \param lhs left-hand-side.
+     431             :        * \param rhs right-hand-side.
+     432             :        * \return    the result of subtracting rhs from lhs.
+     433             :        */
+     434       10009 :       friend flt operator-(const cyclic& lhs, const cyclic& rhs)
+     435             :       {
+     436       10009 :         return diff(lhs, rhs);
+     437             :       }
+     438             : 
+     439             :       protected:
+     440             :         flt val;
+     441             :       };
+     442             : 
+     443             :     /*!
+     444             :      * \brief Implementation of the comparison operation between two angles.
+     445             :      *
+     446             :      * An angle is considered to be smaller than another angle if it is shorter - closer to zero.
+     447             :      *
+     448             :      * \param lhs left-hand-side.
+     449             :      * \param rhs right-hand-side.
+     450             :      * \return    true iff the shortest unsigned walk from lhs to 0 is less than from rhs to 0.
+     451             :      */
+     452             :     template <typename flt, class spec>
+     453           4 :     bool operator<(const cyclic<flt, spec>& lhs, const cyclic<flt, spec>& rhs)
+     454             :     {
+     455           4 :       return cyclic<flt, spec>::dist(lhs, 0) < cyclic<flt, spec>::dist(rhs, 0);
+     456             :     }
+     457             : 
+     458             :     /*!
+     459             :      * \brief Implementation of the comparison operation between two angles.
+     460             :      *
+     461             :      * An angle is considered to be larger than another angle if it is longer - further from zero.
+     462             :      *
+     463             :      * \param lhs left-hand-side.
+     464             :      * \param rhs right-hand-side.
+     465             :      * \return    true iff the shortest unsigned walk from lhs to 0 is more than from rhs to 0.
+     466             :      */
+     467             :     template <typename flt, class spec>
+     468           4 :     bool operator>(const cyclic<flt, spec>& lhs, const cyclic<flt, spec>& rhs)
+     469             :     {
+     470           4 :       return cyclic<flt, spec>::dist(lhs, 0) > cyclic<flt, spec>::dist(rhs, 0);
+     471             :     }
+     472             : 
+     473             :     /*!
+     474             :      * \brief Implementation of the stream output operator.
+     475             :      *
+     476             :      * \param out the stream to write the angle to.
+     477             :      * \param ang the angle to be written.
+     478             :      * \return    a reference to the stream.
+     479             :      */
+     480             :     template <typename flt, class spec>
+     481             :     std::ostream& operator<<(std::ostream &out, const cyclic<flt, spec>& ang)
+     482             :     {
+     483             :       return (out << ang.value());
+     484             :     }
+     485             : 
+     486             :     /*!
+     487             :      * \brief Convenience specialization of the cyclic class for unsigned radians (from $0$ to $2\pi$).
+     488             :      */
+     489             :     struct radians : public cyclic<double, radians>
+     490             :     {
+     491             :       using cyclic<double, radians>::cyclic;  // necessary to inherit constructors
+     492             :       static constexpr double minimum = 0;
+     493             :       static constexpr double supremum = 2 * M_PI;
+     494             :     };
+     495             : 
+     496             :     /*!
+     497             :      * \brief Convenience specialization of the cyclic class for signed radians (from $-\pi$ to $\pi$).
+     498             :      */
+     499             :     struct sradians : public cyclic<double, sradians>
+     500             :     {
+     501             :       using cyclic<double, sradians>::cyclic;  // necessary to inherit constructors
+     502             :       static constexpr double minimum = -M_PI;
+     503             :       static constexpr double supremum = M_PI;
+     504             :     };
+     505             : 
+     506             :     /*!
+     507             :      * \brief Convenience specialization of the cyclic class for unsigned degrees (from $0$ to $360$).
+     508             :      */
+     509             :     struct degrees : public cyclic<double, degrees>
+     510             :     {
+     511             :       using cyclic<double, degrees>::cyclic;  // necessary to inherit constructors
+     512             :       static constexpr double minimum = 0;
+     513             :       static constexpr double supremum = 360;
+     514             :     };
+     515             : 
+     516             :     /*!
+     517             :      * \brief Convenience specialization of the cyclic class for signed degrees (from $-180$ to $180$).
+     518             :      */
+     519             :     struct sdegrees : public cyclic<double, sdegrees>
+     520             :     {
+     521             :       using cyclic<double, sdegrees>::cyclic;  // necessary to inherit constructors
+     522             :       static constexpr double minimum = -180;
+     523             :       static constexpr double supremum = 180;
+     524             :     };
+     525             :   }  // namespace geometry
+     526             : }  // namespace mrs_lib
+     527             : 
+     528             : #endif  // CYCLIC_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/index-sort-f.html b/mrs_lib/include/mrs_lib/geometry/index-sort-f.html new file mode 100644 index 0000000000..0320d0d477 --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometryHitTotalCoverage
Test:coverage.infoLines:659369.9 %
Date:2023-11-29 14:09:54Functions:4712039.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cyclic.h +
67.8%67.8%
+
67.8 %59 / 8737.6 %44 / 117
misc.h +
100.0%
+
100.0 %6 / 6100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/index-sort-l.html b/mrs_lib/include/mrs_lib/geometry/index-sort-l.html new file mode 100644 index 0000000000..b78f4b4a9c --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometryHitTotalCoverage
Test:coverage.infoLines:659369.9 %
Date:2023-11-29 14:09:54Functions:4712039.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cyclic.h +
67.8%67.8%
+
67.8 %59 / 8737.6 %44 / 117
misc.h +
100.0%
+
100.0 %6 / 6100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/index.html b/mrs_lib/include/mrs_lib/geometry/index.html new file mode 100644 index 0000000000..845bbfb791 --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometryHitTotalCoverage
Test:coverage.infoLines:659369.9 %
Date:2023-11-29 14:09:54Functions:4712039.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
cyclic.h +
67.8%67.8%
+
67.8 %59 / 8737.6 %44 / 117
misc.h +
100.0%
+
100.0 %6 / 6100.0 %3 / 3
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/misc.h.func-sort-c.html b/mrs_lib/include/mrs_lib/geometry/misc.h.func-sort-c.html new file mode 100644 index 0000000000..cc58afabef --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/misc.h.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry/misc.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometry - misc.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:66100.0 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry12toHomogenousILi3EEEN5Eigen6MatrixIdXplT_Li1EELi1EXorLNS2_14StorageOptionsE0EquaaeqplT_Li1ELi1EneLi1ELi1ELS4_1EquaaeqLi1ELi1EneplT_Li1ELi1ELS4_0ELS4_0EEXplT_Li1EELi1EEERKNS3_IdXT_ELi1EXorLS4_0EquaaeqT_Li1EneLi1ELi1ELS4_1EquaaeqLi1ELi1EneT_Li1ELS4_0ELS4_0EEXT_ELi1EEE2
_ZN7mrs_lib8geometry14headingFromRotIN5Eigen10QuaternionIdLi0EEEEEdRKT_6
_ZN7mrs_lib8geometry14headingFromRotIN5Eigen6MatrixIdLi3ELi3ELi0ELi3ELi3EEEEEdRKT_6
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/misc.h.func.html b/mrs_lib/include/mrs_lib/geometry/misc.h.func.html new file mode 100644 index 0000000000..f22055d79d --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/misc.h.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry/misc.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometry - misc.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:66100.0 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry12toHomogenousILi3EEEN5Eigen6MatrixIdXplT_Li1EELi1EXorLNS2_14StorageOptionsE0EquaaeqplT_Li1ELi1EneLi1ELi1ELS4_1EquaaeqLi1ELi1EneplT_Li1ELi1ELS4_0ELS4_0EEXplT_Li1EELi1EEERKNS3_IdXT_ELi1EXorLS4_0EquaaeqT_Li1EneLi1ELi1ELS4_1EquaaeqLi1ELi1EneT_Li1ELS4_0ELS4_0EEXT_ELi1EEE2
_ZN7mrs_lib8geometry14headingFromRotIN5Eigen10QuaternionIdLi0EEEEEdRKT_6
_ZN7mrs_lib8geometry14headingFromRotIN5Eigen6MatrixIdLi3ELi3ELi0ELi3ELi3EEEEEdRKT_6
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/geometry/misc.h.gcov.html b/mrs_lib/include/mrs_lib/geometry/misc.h.gcov.html new file mode 100644 index 0000000000..d6c30e5cba --- /dev/null +++ b/mrs_lib/include/mrs_lib/geometry/misc.h.gcov.html @@ -0,0 +1,400 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/geometry/misc.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/geometry - misc.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:66100.0 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : /**  \file
+       3             :      \brief Defines useful geometry utilities and functions.
+       4             :      \author Matouš Vrba - vrbamato@fel.cvut.cz
+       5             :      \author Petr Štibinger - stibipet@fel.cvut.cz
+       6             :  */
+       7             : 
+       8             : #ifndef GEOMETRY_MISC_H
+       9             : #define GEOMETRY_MISC_H
+      10             : 
+      11             : #include <cmath>
+      12             : #include <Eigen/Dense>
+      13             : #include <geometry_msgs/Point.h>
+      14             : #include <geometry_msgs/Quaternion.h>
+      15             : 
+      16             : namespace mrs_lib
+      17             : {
+      18             :   namespace geometry
+      19             :   {
+      20             :     template <int dims>
+      21             :     using vec_t = Eigen::Matrix<double, dims, 1>;
+      22             : 
+      23             :     using pt2_t = vec_t<2>;
+      24             :     using vec2_t = vec_t<2>;
+      25             :     using pt3_t = vec_t<3>;
+      26             :     using vec3_t = vec_t<3>;
+      27             : 
+      28             :     using mat3_t = Eigen::Matrix3d;
+      29             : 
+      30             :     using quat_t = Eigen::Quaterniond;
+      31             :     using anax_t = Eigen::AngleAxisd;
+      32             : 
+      33             :     template <int dims>
+      34           2 :     vec_t<dims + 1> toHomogenous(const vec_t<dims>& vec)
+      35             :     {
+      36           2 :       const Eigen::Matrix<double, dims + 1, 1> ret((Eigen::Matrix<double, dims + 1, 1>() << vec, 1).finished());
+      37           2 :       return ret;
+      38             :     }
+      39             : 
+      40             :     // | ----------------- Angle-related functions ---------------- |
+      41             : 
+      42             :     /* angle-related functions //{ */
+      43             : 
+      44             :     /* headingFromRot() //{ */
+      45             : 
+      46             :     /*!
+      47             :      * \brief Returns the heading angle from the rotation.
+      48             :      *
+      49             :      * Heading is defined as the angle of a [1,0,0] vector rotated by the rotation and projected to the XY plane from the X axis.
+      50             :      *
+      51             :      * \param rot the rotation to extract the heading angle from.
+      52             :      *
+      53             :      * \returns the heading angle.
+      54             :      *
+      55             :      */
+      56             :     template <typename T>
+      57          12 :     double headingFromRot(const T& rot)
+      58             :     {
+      59          12 :       const vec3_t rot_vec = rot*vec3_t::UnitX();
+      60          24 :       return std::atan2(rot_vec.y(), rot_vec.x());
+      61             :     }
+      62             : 
+      63             :     //}
+      64             : 
+      65             :     /* angleBetween() //{ */
+      66             : 
+      67             :     /*!
+      68             :      * \brief Returns the angle between two vectors, taking orientation into account.
+      69             :      *
+      70             :      * This implementation uses \p atan2 instead of just \p acos and thus it properly
+      71             :      * takes into account orientation of the vectors, returning angle in all four quadrants.
+      72             :      *
+      73             :      * \param a vector from which the angle will be measured.
+      74             :      * \param b vector to which the angle will be measured.
+      75             :      *
+      76             :      * \returns    angle from \p a to \p b.
+      77             :      *
+      78             :      */
+      79             :     double angleBetween(const vec2_t& a, const vec2_t& b);
+      80             : 
+      81             :     /*!
+      82             :      * \brief Returns the angle between two vectors, taking orientation into account.
+      83             :      *
+      84             :      * This implementation uses \p atan2 instead of just \p acos and thus it properly
+      85             :      * takes into account orientation of the vectors, returning angle in all four quadrants.
+      86             :      *
+      87             :      * \param a vector from which the angle will be measured.
+      88             :      * \param b vector to which the angle will be measured.
+      89             :      *
+      90             :      * \returns    angle from \p a to \p b.
+      91             :      *
+      92             :      */
+      93             :     double angleBetween(const vec3_t& a, const vec3_t& b);
+      94             : 
+      95             :     //}
+      96             : 
+      97             :     /* angleaxisBetween() //{ */
+      98             : 
+      99             :     /*!
+     100             :      * \brief Returns the rotation between two vectors, represented as angle-axis.
+     101             :      *
+     102             :      * To avoid singularities, a \p tolerance parameter is used:
+     103             :      * * If the absolute angle between the two vectors is less than \p tolerance, a zero rotation is returned.
+     104             :      * * If the angle between the two vectors is closer to \f$ \pi \f$ than \p tolerance, a \f$ \pi \f$ rotation is returned.
+     105             :      *
+     106             :      * \param a vector from which the rotation starts.
+     107             :      * \param b vector at which the rotation ends.
+     108             :      *
+     109             :      * \returns    rotation from \p a to \p b.
+     110             :      *
+     111             :      */
+     112             :     anax_t angleaxisBetween(const vec3_t& a, const vec3_t& b, const double tolerance = 1e-9);
+     113             : 
+     114             :     //}
+     115             : 
+     116             :     /* quaternionBetween() //{ */
+     117             : 
+     118             :     /*!
+     119             :      * \brief Returns the rotation between two vectors, represented as a quaternion.
+     120             :      *
+     121             :      * Works the same as the angleaxisBetween() function (in fact it is used in the implementation).
+     122             :      *
+     123             :      * \param a vector from which the rotation starts.
+     124             :      * \param b vector at which the rotation ends.
+     125             :      *
+     126             :      * \returns    rotation from \p a to \p b.
+     127             :      *
+     128             :      */
+     129             :     quat_t quaternionBetween(const vec3_t& a, const vec3_t& b, const double tolerance = 1e-9);
+     130             : 
+     131             :     //}
+     132             : 
+     133             :     /* rotationBetween() //{ */
+     134             : 
+     135             :     /*!
+     136             :      * \brief Returns the rotation between two vectors, represented as a rotation matrix.
+     137             :      *
+     138             :      * Works the same as the angleaxisBetween() function (in fact it is used in the implementation).
+     139             :      *
+     140             :      * \param a vector from which the rotation starts.
+     141             :      * \param b vector at which the rotation ends.
+     142             :      *
+     143             :      * \returns    rotation from \p a to \p b.
+     144             :      *
+     145             :      */
+     146             :     Eigen::Matrix3d rotationBetween(const vec3_t& a, const vec3_t& b, const double tolerance = 1e-9);
+     147             : 
+     148             :     //}
+     149             : 
+     150             :     /* haversin() //{ */
+     151             : 
+     152             :     /**
+     153             :      * @brief computes the haversine (half of versine) for a given angle
+     154             :      *
+     155             :      * @param angle angle in radians
+     156             :      *
+     157             :      * @return
+     158             :      */
+     159             :     double haversin(const double angle);
+     160             : 
+     161             :     //}
+     162             : 
+     163             :     /* invHaversin() //{ */
+     164             : 
+     165             :     /**
+     166             :      * @brief computes the inverse haversine angle for a given value
+     167             :      *
+     168             :      * @param value
+     169             :      *
+     170             :      * @return angle in radians
+     171             :      */
+     172             :     double invHaversin(const double value);
+     173             : 
+     174             :     //}
+     175             : 
+     176             :     /* solidAngle //{ */
+     177             : 
+     178             :     /**
+     179             :      * @brief computes the solid angle for a spherical surface corresponding to a 'triangle' with edge lengths a, b, c
+     180             :      *
+     181             :      * @param a
+     182             :      * @param b
+     183             :      * @param c
+     184             :      *
+     185             :      * @return solid angle in steradians
+     186             :      */
+     187             :     double solidAngle(double a, double b, double c);
+     188             : 
+     189             :     //}
+     190             : 
+     191             :     /* quaternionFromEuler() //{ */
+     192             : 
+     193             :     /**
+     194             :      * @brief create a quaternion from 3 provided Euler angles
+     195             :      *
+     196             :      * @param x Euler angle in radians
+     197             :      * @param y Euler angle in radians
+     198             :      * @param z Euler angle in radians
+     199             :      *
+     200             :      * @return quaternion
+     201             :      */
+     202             :     quat_t quaternionFromEuler(double x, double y, double z);
+     203             : 
+     204             :     /**
+     205             :      * @brief create a quaternion from Euler angles provided as a vector
+     206             :      *
+     207             :      * @param euler components of the rotation provided as vector of Euler angles
+     208             :      *
+     209             :      * @return quaternion
+     210             :      */
+     211             :     quat_t quaternionFromEuler(const Eigen::Vector3d& euler);
+     212             : 
+     213             :     //}
+     214             : 
+     215             :     /**
+     216             :      * @brief create a quaternion from heading
+     217             :      *
+     218             :      * Heading is defined as the angle of a [1,0,0] vector rotated by the rotation and projected to the XY plane from the X axis.
+     219             :      *
+     220             :      * @param heading the heading angle.
+     221             :      *
+     222             :      * @return the quaternion corresponding to the heading rotation.
+     223             :      */
+     224             :     quat_t quaternionFromHeading(const double heading);
+     225             : 
+     226             :     //}
+     227             : 
+     228             :     // | ----------------- Miscellaneous functions ---------------- |
+     229             : 
+     230             :     /* 2D cross() //{ */
+     231             : 
+     232             :     /*!
+     233             :      * \brief Implementation of cross product for 2D vectors.
+     234             :      *
+     235             :      * Useful e.g. for finding the sine of an angle between two 2D vectors.
+     236             :      *
+     237             :      * \param a first vector of the cross product.
+     238             :      * \param b second vector of the cross product.
+     239             :      *
+     240             :      * \returns    \f$ a \times b \f$ (sine of the angle from \p a to \p b).
+     241             :      *
+     242             :      */
+     243             :     double cross(const vec2_t& a, const vec2_t b);
+     244             : 
+     245             :     //}
+     246             : 
+     247             :     /* vector distance //{ */
+     248             : 
+     249             :     /**
+     250             :      * @brief distnace between two 2D Eigen vectors
+     251             :      *
+     252             :      * @param a
+     253             :      * @param b
+     254             :      *
+     255             :      * @return Euclidean distance
+     256             :      */
+     257             :     double dist(const vec2_t& a, const vec2_t& b);
+     258             : 
+     259             :     /**
+     260             :      * @brief distnace between two 3D Eigen vectors
+     261             :      *
+     262             :      * @param a
+     263             :      * @param b
+     264             :      *
+     265             :      * @return Euclidean distance
+     266             :      */
+     267             :     double dist(const vec3_t& a, const vec3_t& b);
+     268             : 
+     269             :     //}
+     270             : 
+     271             :     /* triangleArea() //{ */
+     272             : 
+     273             :     /**
+     274             :      * @brief uses Heron's formula to compute area of a given triangle using side lengths
+     275             :      *
+     276             :      * @param a length of side1
+     277             :      * @param b length of side2
+     278             :      * @param c length of side3
+     279             :      *
+     280             :      * @return area in units squared
+     281             :      */
+     282             :     double triangleArea(const double a, const double b, const double c);
+     283             : 
+     284             :     //}
+     285             : 
+     286             :     /* sphericalTriangleArea //{ */
+     287             : 
+     288             :     /**
+     289             :      * @brief compute the area of a 'triangle' drawn on a spherical surface
+     290             :      *
+     291             :      * @param a length of side1
+     292             :      * @param b length of side2
+     293             :      * @param c length of side3
+     294             :      *
+     295             :      * @return area in units squared
+     296             :      */
+     297             :     double sphericalTriangleArea(Eigen::Vector3d a, Eigen::Vector3d b, Eigen::Vector3d c);
+     298             : 
+     299             :     //}
+     300             : 
+     301             :     /* rotateCovariance() //{ */
+     302             :     
+     303             :     /*!
+     304             :      * \brief Returns the covariance rotated using the specified rotation.
+     305             :      *
+     306             :      * \param cov the covariance to be rotated.
+     307             :      * \param rot the rotation use.
+     308             :      *
+     309             :      * \returns a new matrix object containing the rotated covariance.
+     310             :      *
+     311             :      */
+     312             :     template <typename T>
+     313             :     mat3_t rotateCovariance(const mat3_t& cov, const T& rot)
+     314             :     {
+     315             :       const mat3_t matrot(rot);
+     316             :       return matrot*cov*matrot.transpose();
+     317             :     }
+     318             :     
+     319             :     //}
+     320             : 
+     321             :   }  // namespace geometry
+     322             : }  // namespace mrs_lib
+     323             : 
+     324             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/gps_conversions.h.func-sort-c.html b/mrs_lib/include/mrs_lib/gps_conversions.h.func-sort-c.html new file mode 100644 index 0000000000..3dc4caeb2a --- /dev/null +++ b/mrs_lib/include/mrs_lib/gps_conversions.h.func-sort-c.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/gps_conversions.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - gps_conversions.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:9213667.6 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_libL19UTMLetterDesignatorEd2
_ZN7mrs_libL7LLtoUTMEddRdS0_Pc2
_ZN7mrs_libL7UTMtoLLEddPKcRdS2_2
_ZN7mrs_libL3UTMEddPdS0_4
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/gps_conversions.h.func.html b/mrs_lib/include/mrs_lib/gps_conversions.h.func.html new file mode 100644 index 0000000000..7c2f22284f --- /dev/null +++ b/mrs_lib/include/mrs_lib/gps_conversions.h.func.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/gps_conversions.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - gps_conversions.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:9213667.6 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_libL19UTMLetterDesignatorEd2
_ZN7mrs_libL3UTMEddPdS0_4
_ZN7mrs_libL7LLtoUTMEddRdS0_Pc2
_ZN7mrs_libL7UTMtoLLEddPKcRdS2_2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/gps_conversions.h.gcov.html b/mrs_lib/include/mrs_lib/gps_conversions.h.gcov.html new file mode 100644 index 0000000000..8b925bb262 --- /dev/null +++ b/mrs_lib/include/mrs_lib/gps_conversions.h.gcov.html @@ -0,0 +1,379 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/gps_conversions.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - gps_conversions.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:9213667.6 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /* Taken from utexas-art-ros-pkg:art_vehicle/applanix */
+       2             : 
+       3             : /*
+       4             :  * Conversions between coordinate systems.
+       5             :  *
+       6             :  * Includes LatLong<->UTM.
+       7             :  */
+       8             : 
+       9             : #ifndef _UTM_H
+      10             : #define _UTM_H
+      11             : 
+      12             : /**  @file
+      13             :      @brief Universal Transverse Mercator transforms.
+      14             :      Functions to convert (spherical) latitude and longitude to and
+      15             :      from (Euclidean) UTM coordinates.
+      16             :      @author Chuck Gantz- chuck.gantz@globalstar.com
+      17             :  */
+      18             : 
+      19             : #include <cmath>
+      20             : #include <cstdio>
+      21             : #include <cstdlib>
+      22             : #include <string>
+      23             : 
+      24             : namespace mrs_lib
+      25             : {
+      26             : 
+      27             :   const double RADIANS_PER_DEGREE = M_PI / 180.0;
+      28             :   const double DEGREES_PER_RADIAN = 180.0 / M_PI;
+      29             : 
+      30             :   // WGS84 Parameters
+      31             :   const double WGS84_A  = 6378137.0;         // major axis
+      32             :   const double WGS84_B  = 6356752.31424518;  // minor axis
+      33             :   const double WGS84_F  = 0.0033528107;      // ellipsoid flattening
+      34             :   const double WGS84_E  = 0.0818191908;      // first eccentricity
+      35             :   const double WGS84_EP = 0.0820944379;      // second eccentricity
+      36             : 
+      37             :   // UTM Parameters
+      38             :   const double UTM_K0   = 0.9996;                   // scale factor
+      39             :   const double UTM_FE   = 500000.0;                 // false easting
+      40             :   const double UTM_FN_N = 0.0;                      // false northing on north hemisphere
+      41             :   const double UTM_FN_S = 10000000.0;               // false northing on south hemisphere
+      42             :   const double UTM_E2   = (WGS84_E * WGS84_E);      // e^2
+      43             :   const double UTM_E4   = (UTM_E2 * UTM_E2);        // e^4
+      44             :   const double UTM_E6   = (UTM_E4 * UTM_E2);        // e^6
+      45             :   const double UTM_EP2  = (UTM_E2 / (1 - UTM_E2));  // e'^2
+      46             : 
+      47             :   /**
+      48             :    * Utility function to convert geodetic to UTM position
+      49             :    *
+      50             :    * Units in are floating point degrees (sign for east/west)
+      51             :    *
+      52             :    * Units out are meters
+      53             :    */
+      54           4 :   static inline void UTM(double lat, double lon, double* x, double* y) {
+      55             :     // constants
+      56             :     const static double m0 = (1 - UTM_E2 / 4 - 3 * UTM_E4 / 64 - 5 * UTM_E6 / 256);
+      57             :     const static double m1 = -(3 * UTM_E2 / 8 + 3 * UTM_E4 / 32 + 45 * UTM_E6 / 1024);
+      58             :     const static double m2 = (15 * UTM_E4 / 256 + 45 * UTM_E6 / 1024);
+      59             :     const static double m3 = -(35 * UTM_E6 / 3072);
+      60             : 
+      61             :     // compute the central meridian
+      62           4 :     int cm = ((lon >= 0.0) ? ((int)lon - ((int)lon) % 6 + 3) : ((int)lon - ((int)lon) % 6 - 3));
+      63             : 
+      64             :     // convert degrees into radians
+      65           4 :     double rlat  = lat * RADIANS_PER_DEGREE;
+      66           4 :     double rlon  = lon * RADIANS_PER_DEGREE;
+      67           4 :     double rlon0 = cm * RADIANS_PER_DEGREE;
+      68             : 
+      69             :     // compute trigonometric functions
+      70           4 :     double slat = sin(rlat);
+      71           4 :     double clat = cos(rlat);
+      72           4 :     double tlat = tan(rlat);
+      73             : 
+      74             :     // decide the false northing at origin
+      75           4 :     double fn = (lat > 0) ? UTM_FN_N : UTM_FN_S;
+      76             : 
+      77           4 :     double T = tlat * tlat;
+      78           4 :     double C = UTM_EP2 * clat * clat;
+      79           4 :     double A = (rlon - rlon0) * clat;
+      80           4 :     double M = WGS84_A * (m0 * rlat + m1 * sin(2 * rlat) + m2 * sin(4 * rlat) + m3 * sin(6 * rlat));
+      81           4 :     double V = WGS84_A / sqrt(1 - UTM_E2 * slat * slat);
+      82             : 
+      83             :     // compute the easting-northing coordinates
+      84           4 :     *x = UTM_FE + UTM_K0 * V * (A + (1 - T + C) * pow(A, 3) / 6 + (5 - 18 * T + T * T + 72 * C - 58 * UTM_EP2) * pow(A, 5) / 120);
+      85           4 :     *y = fn +
+      86           4 :          UTM_K0 *
+      87           4 :              (M + V * tlat * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * pow(A, 4) / 24 + ((61 - 58 * T + T * T + 600 * C - 330 * UTM_EP2) * pow(A, 6) / 720)));
+      88             : 
+      89           4 :     return;
+      90             :   }
+      91             : 
+      92             : 
+      93             :   /**
+      94             :    * Determine the correct UTM letter designator for the
+      95             :    * given latitude
+      96             :    *
+      97             :    * @returns 'Z' if latitude is outside the UTM limits of 84N to 80S
+      98             :    *
+      99             :    * Written by Chuck Gantz- chuck.gantz@globalstar.com
+     100             :    */
+     101           2 :   static inline char UTMLetterDesignator(double Lat) {
+     102             :     char LetterDesignator;
+     103             : 
+     104           2 :     if ((84 >= Lat) && (Lat >= 72))
+     105           0 :       LetterDesignator = 'X';
+     106           2 :     else if ((72 > Lat) && (Lat >= 64))
+     107           0 :       LetterDesignator = 'W';
+     108           2 :     else if ((64 > Lat) && (Lat >= 56))
+     109           0 :       LetterDesignator = 'V';
+     110           2 :     else if ((56 > Lat) && (Lat >= 48))
+     111           0 :       LetterDesignator = 'U';
+     112           2 :     else if ((48 > Lat) && (Lat >= 40))
+     113           0 :       LetterDesignator = 'T';
+     114           2 :     else if ((40 > Lat) && (Lat >= 32))
+     115           0 :       LetterDesignator = 'S';
+     116           2 :     else if ((32 > Lat) && (Lat >= 24))
+     117           0 :       LetterDesignator = 'R';
+     118           2 :     else if ((24 > Lat) && (Lat >= 16))
+     119           0 :       LetterDesignator = 'Q';
+     120           2 :     else if ((16 > Lat) && (Lat >= 8))
+     121           0 :       LetterDesignator = 'P';
+     122           2 :     else if ((8 > Lat) && (Lat >= 0))
+     123           2 :       LetterDesignator = 'N';
+     124           0 :     else if ((0 > Lat) && (Lat >= -8))
+     125           0 :       LetterDesignator = 'M';
+     126           0 :     else if ((-8 > Lat) && (Lat >= -16))
+     127           0 :       LetterDesignator = 'L';
+     128           0 :     else if ((-16 > Lat) && (Lat >= -24))
+     129           0 :       LetterDesignator = 'K';
+     130           0 :     else if ((-24 > Lat) && (Lat >= -32))
+     131           0 :       LetterDesignator = 'J';
+     132           0 :     else if ((-32 > Lat) && (Lat >= -40))
+     133           0 :       LetterDesignator = 'H';
+     134           0 :     else if ((-40 > Lat) && (Lat >= -48))
+     135           0 :       LetterDesignator = 'G';
+     136           0 :     else if ((-48 > Lat) && (Lat >= -56))
+     137           0 :       LetterDesignator = 'F';
+     138           0 :     else if ((-56 > Lat) && (Lat >= -64))
+     139           0 :       LetterDesignator = 'E';
+     140           0 :     else if ((-64 > Lat) && (Lat >= -72))
+     141           0 :       LetterDesignator = 'D';
+     142           0 :     else if ((-72 > Lat) && (Lat >= -80))
+     143           0 :       LetterDesignator = 'C';
+     144             :     // 'Z' is an error flag, the Latitude is outside the UTM limits
+     145             :     else
+     146           0 :       LetterDesignator = 'Z';
+     147           2 :     return LetterDesignator;
+     148             :   }
+     149             : 
+     150             :   /**
+     151             :    * Convert lat/long to UTM coords.  Equations from USGS Bulletin 1532
+     152             :    *
+     153             :    * East Longitudes are positive, West longitudes are negative.
+     154             :    * North latitudes are positive, South latitudes are negative
+     155             :    * Lat and Long are in fractional degrees
+     156             :    *
+     157             :    * Written by Chuck Gantz- chuck.gantz@globalstar.com
+     158             :    */
+     159           2 :   static inline void LLtoUTM(const double Lat, const double Long, double& UTMNorthing, double& UTMEasting, char* UTMZone) {
+     160           2 :     double a          = WGS84_A;
+     161           2 :     double eccSquared = UTM_E2;
+     162           2 :     double k0         = UTM_K0;
+     163             : 
+     164             :     double LongOrigin;
+     165             :     double eccPrimeSquared;
+     166             :     double N, T, C, A, M;
+     167             : 
+     168             :     // Make sure the longitude is between -180.00 .. 179.9
+     169           2 :     double LongTemp = (Long + 180) - int((Long + 180) / 360) * 360 - 180;
+     170             : 
+     171           2 :     double LatRad  = Lat * RADIANS_PER_DEGREE;
+     172           2 :     double LongRad = LongTemp * RADIANS_PER_DEGREE;
+     173             :     double LongOriginRad;
+     174             :     int    ZoneNumber;
+     175             : 
+     176           2 :     ZoneNumber = int((LongTemp + 180) / 6) + 1;
+     177             :     // range clamping to shut up some compiler warnings
+     178             :     // (the UTM Zone number should in reality be in the range <1, 60>)
+     179           2 :     if (ZoneNumber > 99)
+     180           0 :       ZoneNumber = 99;
+     181           2 :     if (ZoneNumber < -9)
+     182           0 :       ZoneNumber = -9;
+     183             : 
+     184           2 :     if (Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0)
+     185           0 :       ZoneNumber = 32;
+     186             : 
+     187             :     // Special zones for Svalbard
+     188           2 :     if (Lat >= 72.0 && Lat < 84.0) {
+     189           0 :       if (LongTemp >= 0.0 && LongTemp < 9.0)
+     190           0 :         ZoneNumber = 31;
+     191           0 :       else if (LongTemp >= 9.0 && LongTemp < 21.0)
+     192           0 :         ZoneNumber = 33;
+     193           0 :       else if (LongTemp >= 21.0 && LongTemp < 33.0)
+     194           0 :         ZoneNumber = 35;
+     195           0 :       else if (LongTemp >= 33.0 && LongTemp < 42.0)
+     196           0 :         ZoneNumber = 37;
+     197             :     }
+     198             :     // +3 puts origin in middle of zone
+     199           2 :     LongOrigin    = (ZoneNumber - 1) * 6 - 180 + 3;
+     200           2 :     LongOriginRad = LongOrigin * RADIANS_PER_DEGREE;
+     201             : 
+     202             :     // compute the UTM Zone from the latitude and longitude
+     203           2 :     snprintf(UTMZone, 4, "%d%c", ZoneNumber, UTMLetterDesignator(Lat));
+     204             : 
+     205           2 :     eccPrimeSquared = (eccSquared) / (1 - eccSquared);
+     206             : 
+     207           2 :     N = a / sqrt(1 - eccSquared * sin(LatRad) * sin(LatRad));
+     208           2 :     T = tan(LatRad) * tan(LatRad);
+     209           2 :     C = eccPrimeSquared * cos(LatRad) * cos(LatRad);
+     210           2 :     A = cos(LatRad) * (LongRad - LongOriginRad);
+     211             : 
+     212           2 :     M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad -
+     213           2 :              (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(2 * LatRad) +
+     214           2 :              (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(4 * LatRad) -
+     215           2 :              (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * LatRad));
+     216             : 
+     217           2 :     UTMEasting =
+     218           2 :         (double)(k0 * N * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120) + 500000.0);
+     219             : 
+     220           2 :     UTMNorthing = (double)(k0 * (M + N * tan(LatRad) *
+     221           2 :                                          (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 +
+     222           2 :                                           (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720)));
+     223           2 :     if (Lat < 0)
+     224           0 :       UTMNorthing += 10000000.0;  // 10000000 meter offset for southern hemisphere
+     225           2 :   }
+     226             : 
+     227             :   static inline void LLtoUTM(const double Lat, const double Long, double& UTMNorthing, double& UTMEasting, std::string& UTMZone) {
+     228             :     char zone_buf[] = {0, 0, 0, 0};
+     229             : 
+     230             :     LLtoUTM(Lat, Long, UTMNorthing, UTMEasting, zone_buf);
+     231             : 
+     232             :     UTMZone = zone_buf;
+     233             :   }
+     234             : 
+     235             : 
+     236             :   /**
+     237             :    * Converts UTM coords to lat/long.  Equations from USGS Bulletin 1532
+     238             :    *
+     239             :    * East Longitudes are positive, West longitudes are negative.
+     240             :    * North latitudes are positive, South latitudes are negative
+     241             :    * Lat and Long are in fractional degrees.
+     242             :    *
+     243             :    * Written by Chuck Gantz- chuck.gantz@globalstar.com
+     244             :    */
+     245           2 :   static inline void UTMtoLL(const double UTMNorthing, const double UTMEasting, const char* UTMZone, double& Lat, double& Long) {
+     246           2 :     double                  k0         = UTM_K0;
+     247           2 :     double                  a          = WGS84_A;
+     248           2 :     double                  eccSquared = UTM_E2;
+     249             :     double                  eccPrimeSquared;
+     250           2 :     double                  e1 = (1 - sqrt(1 - eccSquared)) / (1 + sqrt(1 - eccSquared));
+     251             :     double                  N1, T1, C1, R1, D, M;
+     252             :     double                  LongOrigin;
+     253             :     double                  mu, phi1Rad;
+     254             :     [[maybe_unused]] double phi1;
+     255             :     double                  x, y;
+     256             :     int                     ZoneNumber;
+     257             :     char*                   ZoneLetter;
+     258             :     [[maybe_unused]] int    NorthernHemisphere;  // 1 for northern hemispher, 0 for southern
+     259             : 
+     260           2 :     x = UTMEasting - 500000.0;  // remove 500,000 meter offset for longitude
+     261           2 :     y = UTMNorthing;
+     262             : 
+     263           2 :     ZoneNumber = strtoul(UTMZone, &ZoneLetter, 10);
+     264           2 :     if ((*ZoneLetter - 'N') >= 0)
+     265           2 :       NorthernHemisphere = 1;  // point is in northern hemisphere
+     266             :     else {
+     267           0 :       NorthernHemisphere = 0;  // point is in southern hemisphere
+     268           0 :       y -= 10000000.0;         // remove 10,000,000 meter offset used for southern hemisphere
+     269             :     }
+     270             : 
+     271           2 :     LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3;  //+3 puts origin in middle of zone
+     272             : 
+     273           2 :     eccPrimeSquared = (eccSquared) / (1 - eccSquared);
+     274             : 
+     275           2 :     M  = y / k0;
+     276           2 :     mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));
+     277             : 
+     278           2 :     phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu) +
+     279           2 :               (151 * e1 * e1 * e1 / 96) * sin(6 * mu);
+     280           2 :     phi1 = phi1Rad * DEGREES_PER_RADIAN;
+     281             : 
+     282           2 :     N1 = a / sqrt(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad));
+     283           2 :     T1 = tan(phi1Rad) * tan(phi1Rad);
+     284           2 :     C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad);
+     285           2 :     R1 = a * (1 - eccSquared) / pow(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad), 1.5);
+     286           2 :     D  = x / (N1 * k0);
+     287             : 
+     288           2 :     Lat = phi1Rad - (N1 * tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 +
+     289           2 :                                                 (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);
+     290           2 :     Lat = Lat * DEGREES_PER_RADIAN;
+     291             : 
+     292           2 :     Long = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) /
+     293           2 :            cos(phi1Rad);
+     294           2 :     Long = LongOrigin + Long * DEGREES_PER_RADIAN;
+     295           2 :   }
+     296             : 
+     297             :   static inline void UTMtoLL(const double UTMNorthing, const double UTMEasting, std::string UTMZone, double& Lat, double& Long) {
+     298             :     UTMtoLL(UTMNorthing, UTMEasting, UTMZone.c_str(), Lat, Long);
+     299             :   }
+     300             : 
+     301             : }  // namespace mrs_lib
+     302             : 
+     303             : #endif  // _UTM_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/index-sort-f.html b/mrs_lib/include/mrs_lib/impl/index-sort-f.html new file mode 100644 index 0000000000..d754db4e7e --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/index-sort-f.html @@ -0,0 +1,153 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/implHitTotalCoverage
Test:coverage.infoLines:28940172.1 %
Date:2023-11-29 14:09:54Functions:7511068.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
subscribe_handler.hpp +
57.5%57.5%
+
57.5 %69 / 12055.2 %16 / 29
transformer.hpp +
68.8%68.8%
+
68.8 %44 / 6462.2 %23 / 37
ukf.hpp +
74.0%74.0%
+
74.0 %77 / 10466.7 %8 / 12
param_provider.hpp +
64.3%64.3%
+
64.3 %9 / 1475.0 %12 / 16
timer.hpp +
87.5%87.5%
+
87.5 %14 / 16100.0 %3 / 3
publisher_handler.hpp +
90.0%90.0%
+
90.0 %27 / 30100.0 %4 / 4
service_client_handler.hpp +
92.5%92.5%
+
92.5 %49 / 53100.0 %9 / 9
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/index-sort-l.html b/mrs_lib/include/mrs_lib/impl/index-sort-l.html new file mode 100644 index 0000000000..8dca3c4b49 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/index-sort-l.html @@ -0,0 +1,153 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/implHitTotalCoverage
Test:coverage.infoLines:28940172.1 %
Date:2023-11-29 14:09:54Functions:7511068.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
subscribe_handler.hpp +
57.5%57.5%
+
57.5 %69 / 12055.2 %16 / 29
param_provider.hpp +
64.3%64.3%
+
64.3 %9 / 1475.0 %12 / 16
transformer.hpp +
68.8%68.8%
+
68.8 %44 / 6462.2 %23 / 37
ukf.hpp +
74.0%74.0%
+
74.0 %77 / 10466.7 %8 / 12
timer.hpp +
87.5%87.5%
+
87.5 %14 / 16100.0 %3 / 3
publisher_handler.hpp +
90.0%90.0%
+
90.0 %27 / 30100.0 %4 / 4
service_client_handler.hpp +
92.5%92.5%
+
92.5 %49 / 53100.0 %9 / 9
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/index.html b/mrs_lib/include/mrs_lib/impl/index.html new file mode 100644 index 0000000000..3364803512 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/index.html @@ -0,0 +1,153 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/implHitTotalCoverage
Test:coverage.infoLines:28940172.1 %
Date:2023-11-29 14:09:54Functions:7511068.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
param_provider.hpp +
64.3%64.3%
+
64.3 %9 / 1475.0 %12 / 16
publisher_handler.hpp +
90.0%90.0%
+
90.0 %27 / 30100.0 %4 / 4
service_client_handler.hpp +
92.5%92.5%
+
92.5 %49 / 53100.0 %9 / 9
subscribe_handler.hpp +
57.5%57.5%
+
57.5 %69 / 12055.2 %16 / 29
timer.hpp +
87.5%87.5%
+
87.5 %14 / 16100.0 %3 / 3
transformer.hpp +
68.8%68.8%
+
68.8 %44 / 6462.2 %23 / 37
ukf.hpp +
74.0%74.0%
+
74.0 %77 / 10466.7 %8 / 12
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/param_provider.hpp.func-sort-c.html b/mrs_lib/include/mrs_lib/impl/param_provider.hpp.func-sort-c.html new file mode 100644 index 0000000000..62f57eaaa7 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/param_provider.hpp.func-sort-c.html @@ -0,0 +1,136 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/param_provider.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - param_provider.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:91464.3 %
Date:2023-11-29 14:09:54Functions:121675.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorIfSaIfEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider12getParamImplIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorIfSaIfEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider8getParamIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorIiSaIiEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider12getParamImplIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorIiSaIiEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider8getParamIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider12getParamImplINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_2
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEEbRKS8_RT_2
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorIdSaIdEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_2
_ZNK7mrs_lib13ParamProvider8getParamINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_2
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEEbRKS8_RT_2
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorIdSaIdEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_2
_ZNK7mrs_lib13ParamProvider12getParamImplIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_5
_ZNK7mrs_lib13ParamProvider8getParamIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_5
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/param_provider.hpp.func.html b/mrs_lib/include/mrs_lib/impl/param_provider.hpp.func.html new file mode 100644 index 0000000000..a1c4a1d912 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/param_provider.hpp.func.html @@ -0,0 +1,136 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/param_provider.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - param_provider.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:91464.3 %
Date:2023-11-29 14:09:54Functions:121675.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK7mrs_lib13ParamProvider12getParamImplINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_2
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEEbRKS8_RT_2
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorIdSaIdEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_2
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorIfSaIfEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider12getParamImplISt6vectorIiSaIiEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider12getParamImplIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider12getParamImplIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider12getParamImplIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_5
_ZNK7mrs_lib13ParamProvider8getParamINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_2
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEEbRKS8_RT_2
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorIdSaIdEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_2
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorIfSaIfEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider8getParamISt6vectorIiSaIiEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider8getParamIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_0
_ZNK7mrs_lib13ParamProvider8getParamIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZNK7mrs_lib13ParamProvider8getParamIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_5
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/param_provider.hpp.gcov.html b/mrs_lib/include/mrs_lib/impl/param_provider.hpp.gcov.html new file mode 100644 index 0000000000..efb8b8f8c1 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/param_provider.hpp.gcov.html @@ -0,0 +1,124 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/param_provider.hpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - param_provider.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:91464.3 %
Date:2023-11-29 14:09:54Functions:121675.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef PARAM_PROVIDER_HPP
+       2             : #define PARAM_PROVIDER_HPP
+       3             : 
+       4             : #include <mrs_lib/param_provider.h>
+       5             : 
+       6             : namespace mrs_lib
+       7             : {
+       8             :   template <typename T>
+       9          13 :   bool ParamProvider::getParam(const std::string& param_name, T& value_out) const
+      10             :   {
+      11             :     try
+      12             :     {
+      13          13 :       return getParamImpl(param_name, value_out);
+      14             :     }
+      15           0 :     catch (const YAML::Exception& e)
+      16             :     {
+      17           0 :       ROS_ERROR_STREAM("[" << m_node_name << "]: YAML-CPP threw an unknown exception: " << e.what());
+      18           0 :       return false;
+      19             :     }
+      20             :   }
+      21             : 
+      22             :   template <typename T>
+      23          13 :   bool ParamProvider::getParamImpl(const std::string& param_name, T& value_out) const
+      24             :   {
+      25             :     {
+      26          13 :       const auto found_node = findYamlNode(param_name);
+      27          13 :       if (found_node.has_value())
+      28             :       {
+      29             :         try
+      30             :         {
+      31             :           // try catch is the only type-generic option...
+      32           2 :           value_out = found_node.value().as<T>();
+      33           2 :           return true;
+      34             :         }
+      35           0 :         catch (const YAML::BadConversion& e)
+      36             :         {}
+      37             :       }
+      38             : 
+      39             :     }
+      40             : 
+      41          11 :     if (m_use_rosparam)
+      42          11 :       return m_nh.getParam(param_name, value_out);
+      43             : 
+      44           0 :     return false;
+      45             :   }
+      46             : }
+      47             : 
+      48             : #endif // PARAM_PROVIDER_HPP
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.func-sort-c.html b/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.func-sort-c.html new file mode 100644 index 0000000000..c094feacc7 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.func-sort-c.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/publisher_handler.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - publisher_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:273090.0 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16PublisherHandlerIN8std_msgs6Int64_ISaIvEEEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKjRKbRKd2
_ZN7mrs_lib21PublisherHandler_implIN8std_msgs6Int64_ISaIvEEEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKjRKbRKd2
_ZN7mrs_lib16PublisherHandlerIN8std_msgs6Int64_ISaIvEEEE7publishERKS4_110
_ZN7mrs_lib21PublisherHandler_implIN8std_msgs6Int64_ISaIvEEEE7publishERKS4_110
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.func.html b/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.func.html new file mode 100644 index 0000000000..e4e09b386f --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.func.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/publisher_handler.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - publisher_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:273090.0 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16PublisherHandlerIN8std_msgs6Int64_ISaIvEEEE7publishERKS4_110
_ZN7mrs_lib16PublisherHandlerIN8std_msgs6Int64_ISaIvEEEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKjRKbRKd2
_ZN7mrs_lib21PublisherHandler_implIN8std_msgs6Int64_ISaIvEEEE7publishERKS4_110
_ZN7mrs_lib21PublisherHandler_implIN8std_msgs6Int64_ISaIvEEEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKjRKbRKd2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.gcov.html b/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.gcov.html new file mode 100644 index 0000000000..9f95bb06e6 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/publisher_handler.hpp.gcov.html @@ -0,0 +1,324 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/publisher_handler.hpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - publisher_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:273090.0 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef PUBLISHER_HANDLER_HPP
+       2             : #define PUBLISHER_HANDLER_HPP
+       3             : 
+       4             : namespace mrs_lib
+       5             : {
+       6             : 
+       7             : // --------------------------------------------------------------
+       8             : // |                    PublisherHandler_impl                   |
+       9             : // --------------------------------------------------------------
+      10             : 
+      11             : /* PublisherHandler_impl(void) //{ */
+      12             : 
+      13             : template <class TopicType>
+      14             : PublisherHandler_impl<TopicType>::PublisherHandler_impl(void) : publisher_initialized_(false) {
+      15             : }
+      16             : 
+      17             : //}
+      18             : 
+      19             : /* PublisherHandler_impl(ros::NodeHandle& nh, const std::string& address, const unsigned int &buffer_size, const bool &latch) //{ */
+      20             : 
+      21             : template <class TopicType>
+      22           2 : PublisherHandler_impl<TopicType>::PublisherHandler_impl(ros::NodeHandle& nh, const std::string& address, const unsigned int& buffer_size, const bool& latch,
+      23           2 :                                                         const double& rate) {
+      24             : 
+      25             :   {
+      26           2 :     std::scoped_lock lock(mutex_publisher_);
+      27             : 
+      28           2 :     publisher_ = nh.advertise<TopicType>(address, buffer_size, latch);
+      29             : 
+      30           2 :     if (rate > 0.0) {
+      31             : 
+      32           1 :       throttle_ = true;
+      33             : 
+      34           1 :       throttle_min_dt_ = 1.0 / rate;
+      35             : 
+      36             :     } else {
+      37             : 
+      38           1 :       throttle_ = false;
+      39             : 
+      40           1 :       throttle_min_dt_ = 0;
+      41             :     }
+      42             : 
+      43           2 :     last_time_published_ = ros::Time(0);
+      44             :   }
+      45             : 
+      46           2 :   publisher_initialized_ = true;
+      47           2 : }
+      48             : 
+      49             : //}
+      50             : 
+      51             : /* publish(TopicType& msg) //{ */
+      52             : 
+      53             : template <class TopicType>
+      54         110 : void PublisherHandler_impl<TopicType>::publish(const TopicType& msg) {
+      55             : 
+      56         110 :   if (!publisher_initialized_) {
+      57           0 :     return;
+      58             :   }
+      59             : 
+      60             :   {
+      61         110 :     std::scoped_lock lock(mutex_publisher_);
+      62             : 
+      63         110 :     if (throttle_) {
+      64             : 
+      65         100 :       if ((ros::Time::now() - last_time_published_).toSec() < throttle_min_dt_) {
+      66          90 :         return;
+      67             :       }
+      68             : 
+      69          10 :       last_time_published_ = ros::Time::now();
+      70             :     }
+      71             : 
+      72             :     try {
+      73          20 :       publisher_.publish(msg);
+      74             :     }
+      75           0 :     catch (...) {
+      76           0 :       ROS_ERROR("exception caught during publishing topic '%s'", publisher_.getTopic().c_str());
+      77             :     }
+      78             :   }
+      79             : }
+      80             : 
+      81             : //}
+      82             : 
+      83             : /* publish(const boost::shared_ptr<TopicType>& msg) //{ */
+      84             : 
+      85             : template <class TopicType>
+      86             : void PublisherHandler_impl<TopicType>::publish(const boost::shared_ptr<TopicType>& msg) {
+      87             : 
+      88             :   if (!publisher_initialized_) {
+      89             :     return;
+      90             :   }
+      91             : 
+      92             :   {
+      93             :     std::scoped_lock lock(mutex_publisher_);
+      94             : 
+      95             :     if (throttle_) {
+      96             : 
+      97             :       if ((ros::Time::now() - last_time_published_).toSec() < throttle_min_dt_) {
+      98             :         return;
+      99             :       }
+     100             : 
+     101             :       last_time_published_ = ros::Time::now();
+     102             :     }
+     103             : 
+     104             :     try {
+     105             :       publisher_.publish(msg);
+     106             :     }
+     107             :     catch (...) {
+     108             :       ROS_ERROR("exception caught during publishing topic '%s'", publisher_.getTopic().c_str());
+     109             :     }
+     110             :   }
+     111             : }
+     112             : 
+     113             : //}
+     114             : 
+     115             : /* publish(const boost::shared_ptr<TopicType const>& msg) //{ */
+     116             : 
+     117             : template <class TopicType>
+     118             : void PublisherHandler_impl<TopicType>::publish(const boost::shared_ptr<TopicType const>& msg) {
+     119             : 
+     120             :   if (!publisher_initialized_) {
+     121             :     return;
+     122             :   }
+     123             : 
+     124             :   {
+     125             :     std::scoped_lock lock(mutex_publisher_);
+     126             : 
+     127             :     if (throttle_) {
+     128             : 
+     129             :       if ((ros::Time::now() - last_time_published_).toSec() < throttle_min_dt_) {
+     130             :         return;
+     131             :       }
+     132             : 
+     133             :       last_time_published_ = ros::Time::now();
+     134             :     }
+     135             : 
+     136             :     try {
+     137             :       publisher_.publish(msg);
+     138             :     }
+     139             :     catch (...) {
+     140             :       ROS_ERROR("exception caught during publishing topic '%s'", publisher_.getTopic().c_str());
+     141             :     }
+     142             :   }
+     143             : }
+     144             : 
+     145             : //}
+     146             : 
+     147             : /* getNumSubscribers(void) //{ */
+     148             : 
+     149             : template <class TopicType>
+     150             : unsigned int PublisherHandler_impl<TopicType>::getNumSubscribers(void) {
+     151             : 
+     152             :   {
+     153             :     std::scoped_lock lock(mutex_publisher_);
+     154             : 
+     155             :     return publisher_.getNumSubscribers();
+     156             :   }
+     157             : }
+     158             : 
+     159             : //}
+     160             : 
+     161             : // --------------------------------------------------------------
+     162             : // |                      PublisherHandler                      |
+     163             : // --------------------------------------------------------------
+     164             : 
+     165             : /* operator= //{ */
+     166             : 
+     167             : template <class TopicType>
+     168             : PublisherHandler<TopicType>& PublisherHandler<TopicType>::operator=(const PublisherHandler<TopicType>& other) {
+     169             : 
+     170             :   if (this == &other) {
+     171             :     return *this;
+     172             :   }
+     173             : 
+     174             :   if (other.impl_) {
+     175             :     this->impl_ = other.impl_;
+     176             :   }
+     177             : 
+     178             :   return *this;
+     179             : }
+     180             : 
+     181             : //}
+     182             : 
+     183             : /* copy constructor //{ */
+     184             : 
+     185             : template <class TopicType>
+     186             : PublisherHandler<TopicType>::PublisherHandler(const PublisherHandler<TopicType>& other) {
+     187             : 
+     188             :   if (other.impl_) {
+     189             :     this->impl_ = other.impl_;
+     190             :   }
+     191             : }
+     192             : 
+     193             : //}
+     194             : 
+     195             : /* PublisherHandler(ros::NodeHandle& nh, const std::string& address, const unsigned int &buffer_size, const bool &latch) //{ */
+     196             : 
+     197             : template <class TopicType>
+     198           2 : PublisherHandler<TopicType>::PublisherHandler(ros::NodeHandle& nh, const std::string& address, const unsigned int& buffer_size, const bool& latch,
+     199           2 :                                               const double& rate) {
+     200             : 
+     201           2 :   impl_ = std::make_shared<PublisherHandler_impl<TopicType>>(nh, address, buffer_size, latch, rate);
+     202           2 : }
+     203             : 
+     204             : //}
+     205             : 
+     206             : /* publish(const TopicType& msg) //{ */
+     207             : 
+     208             : template <class TopicType>
+     209         110 : void PublisherHandler<TopicType>::publish(const TopicType& msg) {
+     210             : 
+     211         110 :   impl_->publish(msg);
+     212         110 : }
+     213             : 
+     214             : //}
+     215             : 
+     216             : /* publish(const boost::shared_ptr<TopicType>& msg) //{ */
+     217             : 
+     218             : template <class TopicType>
+     219             : void PublisherHandler<TopicType>::publish(const boost::shared_ptr<TopicType>& msg) {
+     220             : 
+     221             :   impl_->publish(msg);
+     222             : }
+     223             : 
+     224             : //}
+     225             : 
+     226             : /* publish(const boost::shared_ptr<TopicType const>& msg) //{ */
+     227             : 
+     228             : template <class TopicType>
+     229             : void PublisherHandler<TopicType>::publish(const boost::shared_ptr<TopicType const>& msg) {
+     230             : 
+     231             :   impl_->publish(msg);
+     232             : }
+     233             : 
+     234             : //}
+     235             : 
+     236             : /* getNumSubscribers(void) //{ */
+     237             : 
+     238             : template <class TopicType>
+     239             : unsigned int PublisherHandler<TopicType>::getNumSubscribers(void) {
+     240             : 
+     241             :   return impl_->getNumSubscribers();
+     242             : }
+     243             : 
+     244             : //}
+     245             : 
+     246             : }  // namespace mrs_lib
+     247             : 
+     248             : #endif  // PUBLISHER_HANDLER_HPP
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.func-sort-c.html b/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.func-sort-c.html new file mode 100644 index 0000000000..e08a7c1d95 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.func-sort-c.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/service_client_handler.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - service_client_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:495392.5 %
Date:2023-11-29 14:09:54Functions:99100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEE4callERS2_1
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE4callERS2_1
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEE9callAsyncERS2_RKi2
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEEaSERKS3_2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE4callERS2_RKiRKd2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE8asyncRunEv2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE9callAsyncERS2_RKi2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.func.html b/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.func.html new file mode 100644 index 0000000000..1b5a1adcb3 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.func.html @@ -0,0 +1,108 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/service_client_handler.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - service_client_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:495392.5 %
Date:2023-11-29 14:09:54Functions:99100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEE4callERS2_1
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEE9callAsyncERS2_RKi2
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEEaSERKS3_2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE4callERS2_1
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE4callERS2_RKiRKd2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE8asyncRunEv2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEE9callAsyncERS2_RKi2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEEC2ERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.gcov.html b/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.gcov.html new file mode 100644 index 0000000000..730e61a88f --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/service_client_handler.hpp.gcov.html @@ -0,0 +1,395 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/service_client_handler.hpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - service_client_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:495392.5 %
Date:2023-11-29 14:09:54Functions:99100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef SERVICE_CLIENT_HANDLER_HPP
+       2             : #define SERVICE_CLIENT_HANDLER_HPP
+       3             : 
+       4             : namespace mrs_lib
+       5             : {
+       6             : 
+       7             : // --------------------------------------------------------------
+       8             : // |                  ServiceClientHandler_impl                 |
+       9             : // --------------------------------------------------------------
+      10             : 
+      11             : /* ServiceClientHandler_impl(void) //{ */
+      12             : 
+      13             : template <class ServiceType>
+      14             : ServiceClientHandler_impl<ServiceType>::ServiceClientHandler_impl(void) : service_initialized_(false) {
+      15             : }
+      16             : 
+      17             : //}
+      18             : 
+      19             : /* ServiceClientHandler_impl(ros::NodeHandle& nh, const std::string& address) //{ */
+      20             : 
+      21             : template <class ServiceType>
+      22           2 : ServiceClientHandler_impl<ServiceType>::ServiceClientHandler_impl(ros::NodeHandle& nh, const std::string& address) {
+      23             : 
+      24             :   {
+      25           2 :     std::scoped_lock lock(mutex_service_client_);
+      26             : 
+      27           2 :     service_client_ = nh.serviceClient<ServiceType>(address);
+      28             :   }
+      29             : 
+      30           2 :   _address_       = address;
+      31           2 :   async_attempts_ = 1;
+      32             : 
+      33             :   /* thread_oneshot_ = std::make_shared<std::thread>(std::thread(&ServiceClientHandler_impl::threadOneshot, this, true, false)); */
+      34             : 
+      35           2 :   service_initialized_ = true;
+      36           2 : }
+      37             : 
+      38             : //}
+      39             : 
+      40             : /* call(ServiceType& srv) //{ */
+      41             : 
+      42             : template <class ServiceType>
+      43           1 : bool ServiceClientHandler_impl<ServiceType>::call(ServiceType& srv) {
+      44             : 
+      45           1 :   if (!service_initialized_) {
+      46           0 :     return false;
+      47             :   }
+      48             : 
+      49           1 :   return service_client_.call(srv);
+      50             : }
+      51             : 
+      52             : //}
+      53             : 
+      54             : /* call(ServiceType& srv, const int& attempts) //{ */
+      55             : 
+      56             : template <class ServiceType>
+      57             : bool ServiceClientHandler_impl<ServiceType>::call(ServiceType& srv, const int& attempts) {
+      58             : 
+      59             :   if (!service_initialized_) {
+      60             :     return false;
+      61             :   }
+      62             : 
+      63             :   std::scoped_lock lock(mutex_service_client_);
+      64             : 
+      65             :   bool success = false;
+      66             :   int  counter = 0;
+      67             : 
+      68             :   while (!success && ros::ok()) {
+      69             : 
+      70             :     success = service_client_.call(srv);
+      71             : 
+      72             :     if (!success) {
+      73             :       ROS_ERROR("[%s]: failed to call service to '%s'", ros::this_node::getName().c_str(), _address_.c_str());
+      74             :     }
+      75             : 
+      76             :     if (++counter >= attempts) {
+      77             :       break;
+      78             :     }
+      79             :   }
+      80             : 
+      81             :   return success;
+      82             : }
+      83             : 
+      84             : //}
+      85             : 
+      86             : /* call(ServiceType& srv, const int& attempts, const double& repeat_delay) //{ */
+      87             : 
+      88             : template <class ServiceType>
+      89           2 : bool ServiceClientHandler_impl<ServiceType>::call(ServiceType& srv, const int& attempts, const double& repeat_delay) {
+      90             : 
+      91           2 :   if (!service_initialized_) {
+      92           0 :     return false;
+      93             :   }
+      94             : 
+      95           2 :   std::scoped_lock lock(mutex_service_client_);
+      96             : 
+      97           2 :   bool success = false;
+      98           2 :   int  counter = 0;
+      99             : 
+     100           8 :   while (!success && ros::ok()) {
+     101             : 
+     102           6 :     success = service_client_.call(srv);
+     103             : 
+     104           6 :     if (!success) {
+     105           4 :       ROS_ERROR("[%s]: failed to call service to '%s'", ros::this_node::getName().c_str(), _address_.c_str());
+     106             :     }
+     107             : 
+     108           6 :     if (++counter >= attempts) {
+     109           0 :       break;
+     110             :     }
+     111             : 
+     112           6 :     ros::Duration(repeat_delay).sleep();
+     113             :   }
+     114             : 
+     115           2 :   return success;
+     116             : }
+     117             : 
+     118             : //}
+     119             : 
+     120             : /* callAsync(ServiceType& srv) //{ */
+     121             : 
+     122             : template <class ServiceType>
+     123             : std::future<ServiceType> ServiceClientHandler_impl<ServiceType>::callAsync(ServiceType& srv) {
+     124             : 
+     125             :   {
+     126             :     std::scoped_lock lock(mutex_async_);
+     127             : 
+     128             :     async_data_         = srv;
+     129             :     async_attempts_     = 1;
+     130             :     async_repeat_delay_ = 0;
+     131             :   }
+     132             : 
+     133             :   return std::async(std::launch::async, &ServiceClientHandler_impl::asyncRun, this);
+     134             : }
+     135             : 
+     136             : //}
+     137             : 
+     138             : /* callAsync(ServiceType& srv, const int& attempts) //{ */
+     139             : 
+     140             : template <class ServiceType>
+     141           2 : std::future<ServiceType> ServiceClientHandler_impl<ServiceType>::callAsync(ServiceType& srv, const int& attempts) {
+     142             : 
+     143             :   {
+     144           2 :     std::scoped_lock lock(mutex_async_);
+     145             : 
+     146           2 :     async_data_         = srv;
+     147           2 :     async_attempts_     = attempts;
+     148           2 :     async_repeat_delay_ = 0;
+     149             :   }
+     150             : 
+     151           2 :   return std::async(std::launch::async, &ServiceClientHandler_impl::asyncRun, this);
+     152             : }
+     153             : 
+     154             : //}
+     155             : 
+     156             : /* callAsync(ServiceType& srv, const int& attempts, const double &repeat_delay) //{ */
+     157             : 
+     158             : template <class ServiceType>
+     159             : std::future<ServiceType> ServiceClientHandler_impl<ServiceType>::callAsync(ServiceType& srv, const int& attempts, const double& repeat_delay) {
+     160             : 
+     161             :   {
+     162             :     std::scoped_lock lock(mutex_async_);
+     163             : 
+     164             :     async_data_         = srv;
+     165             :     async_attempts_     = attempts;
+     166             :     async_repeat_delay_ = repeat_delay;
+     167             :   }
+     168             : 
+     169             :   return std::async(std::launch::async, &ServiceClientHandler_impl::asyncRun, this);
+     170             : }
+     171             : 
+     172             : //}
+     173             : 
+     174             : /* asyncRun(void) //{ */
+     175             : 
+     176             : template <class ServiceType>
+     177           2 : ServiceType ServiceClientHandler_impl<ServiceType>::asyncRun(void) {
+     178             : 
+     179           2 :   ServiceType async_data;
+     180             :   int         async_attempts;
+     181             : 
+     182             :   {
+     183           2 :     std::scoped_lock lock(mutex_async_);
+     184             : 
+     185           2 :     async_data          = async_data_;
+     186           2 :     async_attempts      = async_attempts_;
+     187           2 :     async_repeat_delay_ = async_repeat_delay_;
+     188             :   }
+     189             : 
+     190           2 :   call(async_data, async_attempts, async_repeat_delay_);
+     191             : 
+     192           4 :   return async_data;
+     193             : }
+     194             : 
+     195             : //}
+     196             : 
+     197             : // --------------------------------------------------------------
+     198             : // |                    ServiceClientHandler                    |
+     199             : // --------------------------------------------------------------
+     200             : 
+     201             : /* operator= //{ */
+     202             : 
+     203             : template <class ServiceType>
+     204           2 : ServiceClientHandler<ServiceType>& ServiceClientHandler<ServiceType>::operator=(const ServiceClientHandler<ServiceType>& other) {
+     205             : 
+     206           2 :   if (this == &other) {
+     207           0 :     return *this;
+     208             :   }
+     209             : 
+     210           2 :   if (other.impl_) {
+     211           2 :     this->impl_ = other.impl_;
+     212             :   }
+     213             : 
+     214           2 :   return *this;
+     215             : }
+     216             : 
+     217             : //}
+     218             : 
+     219             : /* copy constructor //{ */
+     220             : 
+     221             : template <class ServiceType>
+     222             : ServiceClientHandler<ServiceType>::ServiceClientHandler(const ServiceClientHandler<ServiceType>& other) {
+     223             : 
+     224             :   if (other.impl_) {
+     225             :     this->impl_ = other.impl_;
+     226             :   }
+     227             : }
+     228             : 
+     229             : //}
+     230             : 
+     231             : /* ServiceClientHandler(ros::NodeHandle& nh, const std::string& address) //{ */
+     232             : 
+     233             : template <class ServiceType>
+     234           2 : ServiceClientHandler<ServiceType>::ServiceClientHandler(ros::NodeHandle& nh, const std::string& address) {
+     235             : 
+     236           2 :   impl_ = std::make_shared<ServiceClientHandler_impl<ServiceType>>(nh, address);
+     237           2 : }
+     238             : 
+     239             : //}
+     240             : 
+     241             : /* initialize(ros::NodeHandle& nh, const std::string& address) //{ */
+     242             : 
+     243             : template <class ServiceType>
+     244             : void ServiceClientHandler<ServiceType>::initialize(ros::NodeHandle& nh, const std::string& address) {
+     245             : 
+     246             :   impl_ = std::make_shared<ServiceClientHandler_impl<ServiceType>>(nh, address);
+     247             : }
+     248             : 
+     249             : //}
+     250             : 
+     251             : /* call(ServiceType& srv) //{ */
+     252             : 
+     253             : template <class ServiceType>
+     254           1 : bool ServiceClientHandler<ServiceType>::call(ServiceType& srv) {
+     255             : 
+     256           1 :   return impl_->call(srv);
+     257             : }
+     258             : 
+     259             : //}
+     260             : 
+     261             : /* call(ServiceType& srv, const int& attempts) //{ */
+     262             : 
+     263             : template <class ServiceType>
+     264             : bool ServiceClientHandler<ServiceType>::call(ServiceType& srv, const int& attempts) {
+     265             : 
+     266             :   return impl_->call(srv, attempts);
+     267             : }
+     268             : 
+     269             : //}
+     270             : 
+     271             : /* call(ServiceType& srv, const int& attempts, const double& repeat_delay) //{ */
+     272             : 
+     273             : template <class ServiceType>
+     274             : bool ServiceClientHandler<ServiceType>::call(ServiceType& srv, const int& attempts, const double& repeat_delay) {
+     275             : 
+     276             :   return impl_->call(srv, attempts, repeat_delay);
+     277             : }
+     278             : 
+     279             : //}
+     280             : 
+     281             : /* callAsync(ServiceType& srv) //{ */
+     282             : 
+     283             : template <class ServiceType>
+     284             : std::future<ServiceType> ServiceClientHandler<ServiceType>::callAsync(ServiceType& srv) {
+     285             : 
+     286             :   std::future<ServiceType> res = impl_->callAsync(srv);
+     287             : 
+     288             :   return res;
+     289             : }
+     290             : 
+     291             : //}
+     292             : 
+     293             : /* callAsync(ServiceType& srv, const int& attempts) //{ */
+     294             : 
+     295             : template <class ServiceType>
+     296           2 : std::future<ServiceType> ServiceClientHandler<ServiceType>::callAsync(ServiceType& srv, const int& attempts) {
+     297             : 
+     298           2 :   std::future<ServiceType> res = impl_->callAsync(srv, attempts);
+     299             : 
+     300           2 :   return res;
+     301             : }
+     302             : 
+     303             : //}
+     304             : 
+     305             : /* callAsync(ServiceType& srv, const int& attempts, const double& repeat_delay) //{ */
+     306             : 
+     307             : template <class ServiceType>
+     308             : std::future<ServiceType> ServiceClientHandler<ServiceType>::callAsync(ServiceType& srv, const int& attempts, const double& repeat_delay) {
+     309             : 
+     310             :   std::future<ServiceType> res = impl_->callAsync(srv, attempts, repeat_delay);
+     311             : 
+     312             :   return res;
+     313             : }
+     314             : 
+     315             : //}
+     316             : 
+     317             : }  // namespace mrs_lib
+     318             : 
+     319             : #endif  // SERVICE_CLIENT_HANDLER_HPP
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.func-sort-c.html b/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.func-sort-c.html new file mode 100644 index 0000000000..9a099f7d31 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.func-sort-c.html @@ -0,0 +1,188 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - subscribe_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:6912057.5 %
Date:2023-11-29 14:09:54Functions:162955.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe6getMsgEv0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl10waitForNewERKN3ros12WallDurationE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl13data_callbackERKN5boost10shared_ptrIKS4_EE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl24default_timeout_callbackERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl6getMsgEv0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4ImplD0Ev0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe6newMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe7peekMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe7usedMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe9topicNameB5cxx11Ev0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl6newMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl7peekMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl7usedMsgEv0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafeC2ERKNS_23SubscribeHandlerOptionsERKSt8functionIFvN5boost10shared_ptrIKS4_EEEE1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafeD0Ev1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafeD2Ev1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4ImplC2ERKNS_23SubscribeHandlerOptionsERKSt8functionIFvN5boost10shared_ptrIKS4_EEEE1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4ImplD2Ev1
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl9topicNameB5cxx11Ev2
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe4stopEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe5startEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl4stopEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl5startEv5
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe11lastMsgTimeEv5
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl11lastMsgTimeEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe13data_callbackERKN5boost10shared_ptrIKS4_EE20
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl19process_new_messageERKN5boost10shared_ptrIKS4_EE20
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe6hasMsgEv10000
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl6hasMsgEv10000
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.func.html b/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.func.html new file mode 100644 index 0000000000..2818afa181 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.func.html @@ -0,0 +1,188 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - subscribe_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:6912057.5 %
Date:2023-11-29 14:09:54Functions:162955.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe13data_callbackERKN5boost10shared_ptrIKS4_EE20
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe4stopEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe5startEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe6getMsgEv0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafeC2ERKNS_23SubscribeHandlerOptionsERKSt8functionIFvN5boost10shared_ptrIKS4_EEEE1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafeD0Ev1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafeD2Ev1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl10waitForNewERKN3ros12WallDurationE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl13data_callbackERKN5boost10shared_ptrIKS4_EE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl19process_new_messageERKN5boost10shared_ptrIKS4_EE20
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl24default_timeout_callbackERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl4stopEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl5startEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl6getMsgEv0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4ImplC2ERKNS_23SubscribeHandlerOptionsERKSt8functionIFvN5boost10shared_ptrIKS4_EEEE1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4ImplD0Ev0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4ImplD2Ev1
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe11lastMsgTimeEv5
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe6hasMsgEv10000
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe6newMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe7peekMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe7usedMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE14ImplThreadsafe9topicNameB5cxx11Ev0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl11lastMsgTimeEv5
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl6hasMsgEv10000
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl6newMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl7peekMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl7usedMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4Impl9topicNameB5cxx11Ev2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.gcov.html b/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.gcov.html new file mode 100644 index 0000000000..646aef5d3f --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp.gcov.html @@ -0,0 +1,405 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/subscribe_handler.hpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - subscribe_handler.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:6912057.5 %
Date:2023-11-29 14:09:54Functions:162955.2 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : 
+       3             : #ifndef SUBSCRIBE_HANDLER_HPP
+       4             : #define SUBSCRIBE_HANDLER_HPP
+       5             : 
+       6             : #include <mrs_lib/subscribe_handler.h>
+       7             : #include <mrs_lib/timer.h>
+       8             : #include <mutex>
+       9             : #include <condition_variable>
+      10             : 
+      11             : namespace mrs_lib
+      12             : {
+      13             :   /* SubscribeHandler::Impl class //{ */
+      14             :   // implements the constructor, getMsg() method and data_callback method (non-thread-safe)
+      15             :   template <typename MessageType>
+      16             :   class SubscribeHandler<MessageType>::Impl
+      17             :   {
+      18             :   public:
+      19             :     using timeout_callback_t = typename SubscribeHandler<MessageType>::timeout_callback_t;
+      20             :     using message_callback_t = typename SubscribeHandler<MessageType>::message_callback_t;
+      21             :     using data_callback_t = std::function<void(const typename MessageType::ConstPtr&)>;
+      22             : 
+      23             :   private:
+      24             :     friend class SubscribeHandler<MessageType>;
+      25             : 
+      26             :   public:
+      27             :     /* constructor //{ */
+      28           1 :     Impl(const SubscribeHandlerOptions& options, const message_callback_t& message_callback = message_callback_t())
+      29           1 :         : m_nh(options.nh),
+      30           1 :           m_topic_name(options.topic_name),
+      31           1 :           m_node_name(options.node_name),
+      32             :           m_got_data(false),
+      33             :           m_new_data(false),
+      34             :           m_used_data(false),
+      35           1 :           m_timeout_manager(options.timeout_manager),
+      36             :           m_latest_message_time(0),
+      37             :           m_latest_message(nullptr),
+      38             :           m_message_callback(message_callback),
+      39           1 :           m_queue_size(options.queue_size),
+      40           1 :           m_transport_hints(options.transport_hints)
+      41             :     {
+      42           1 :       if (options.no_message_timeout != mrs_lib::no_timeout)
+      43             :       {
+      44             :         // initialize a new TimeoutManager if not provided by the user
+      45           1 :         if (!m_timeout_manager)
+      46           1 :           m_timeout_manager = std::make_shared<mrs_lib::TimeoutManager>(m_nh, ros::Rate(2.0/options.no_message_timeout.toSec()));
+      47             : 
+      48             :         // initialize the callback for the TimeoutManager
+      49           2 :         std::function<void(const ros::Time&)> timeout_mgr_callback;
+      50           1 :         if (options.timeout_callback)
+      51           1 :           timeout_mgr_callback = std::bind(options.timeout_callback, topicName(), std::placeholders::_1);
+      52             :         else
+      53           0 :           timeout_mgr_callback = std::bind(&Impl::default_timeout_callback, this, topicName(), std::placeholders::_1);
+      54             : 
+      55             :         // register the timeout callback with the TimeoutManager
+      56           1 :         m_timeout_id = m_timeout_manager->registerNew(options.no_message_timeout, timeout_mgr_callback);
+      57             :       }
+      58             : 
+      59           3 :       const std::string msg = "Subscribed to topic '" + m_topic_name + "' -> '" + topicName() + "'";
+      60           1 :       if (m_node_name.empty())
+      61           1 :         ROS_INFO_STREAM(msg);
+      62             :       else
+      63           0 :         ROS_INFO_STREAM("[" << m_node_name << "]: " << msg);
+      64           1 :     }
+      65             :     //}
+      66             : 
+      67           1 :     virtual ~Impl() = default;
+      68             : 
+      69             :   public:
+      70             :     /* getMsg() method //{ */
+      71           0 :     virtual typename MessageType::ConstPtr getMsg()
+      72             :     {
+      73           0 :       m_new_data = false;
+      74           0 :       m_used_data = true;
+      75           0 :       return peekMsg();
+      76             :     }
+      77             :     //}
+      78             : 
+      79             :     /* peekMsg() method //{ */
+      80           0 :     virtual typename MessageType::ConstPtr peekMsg() const
+      81             :     {
+      82             :       /* assert(m_got_data); */
+      83             :       /* if (!m_got_data) */
+      84             :       /*   ROS_ERROR("[%s]: No data received yet from topic '%s' (forgot to check hasMsg()?)! Returning empty message.", m_node_name.c_str(), */
+      85             :       /*             topicName().c_str()); */
+      86           0 :       return m_latest_message;
+      87             :     }
+      88             :     //}
+      89             : 
+      90             :     /* hasMsg() method //{ */
+      91       10000 :     virtual bool hasMsg() const
+      92             :     {
+      93       10000 :       return m_got_data;
+      94             :     }
+      95             :     //}
+      96             : 
+      97             :     /* newMsg() method //{ */
+      98           0 :     virtual bool newMsg() const
+      99             :     {
+     100           0 :       return m_new_data;
+     101             :     }
+     102             :     //}
+     103             : 
+     104             :     /* usedMsg() method //{ */
+     105           0 :     virtual bool usedMsg() const
+     106             :     {
+     107           0 :       return m_used_data;
+     108             :     }
+     109             :     //}
+     110             : 
+     111             :     /* waitForNew() method //{ */
+     112           0 :     virtual typename MessageType::ConstPtr waitForNew(const ros::WallDuration& timeout)
+     113             :     {
+     114             :       // convert the ros type to chrono type
+     115           0 :       const std::chrono::duration<float> chrono_timeout(timeout.toSec());
+     116             :       // lock the mutex guarding the m_new_data flag
+     117           0 :       std::unique_lock lock(m_new_data_mtx);
+     118             :       // if new data is available, return immediately, otherwise attempt to wait for new data using the respective condition variable
+     119           0 :       if (m_new_data)
+     120           0 :         return getMsg();
+     121           0 :       else if (m_new_data_cv.wait_for(lock, chrono_timeout) == std::cv_status::no_timeout && m_new_data)
+     122           0 :         return getMsg();
+     123             :       else
+     124           0 :         return nullptr;
+     125             :     };
+     126             :     //}
+     127             : 
+     128             :     /* lastMsgTime() method //{ */
+     129           5 :     virtual ros::Time lastMsgTime() const
+     130             :     {
+     131           5 :       return m_latest_message_time;
+     132             :     };
+     133             :     //}
+     134             : 
+     135             :     /* topicName() method //{ */
+     136           2 :     virtual std::string topicName() const
+     137             :     {
+     138           2 :       std::string ret = m_sub.getTopic();
+     139           2 :       if (ret.empty())
+     140           2 :         ret = m_nh.resolveName(m_topic_name);
+     141           2 :       return ret;
+     142             :     }
+     143             :     //}
+     144             : 
+     145             :     /* start() method //{ */
+     146           5 :     virtual void start()
+     147             :     {
+     148           5 :       if (m_timeout_manager)
+     149           5 :         m_timeout_manager->start(m_timeout_id);
+     150           5 :       m_sub = m_nh.subscribe(m_topic_name, m_queue_size, &Impl::data_callback, this, m_transport_hints);
+     151           5 :     }
+     152             :     //}
+     153             : 
+     154             :     /* stop() method //{ */
+     155           5 :     virtual void stop()
+     156             :     {
+     157           5 :       if (m_timeout_manager)
+     158           5 :         m_timeout_manager->pause(m_timeout_id);
+     159           5 :       m_sub.shutdown();
+     160           5 :     }
+     161             :     //}
+     162             : 
+     163             :   protected:
+     164             :     ros::NodeHandle m_nh;
+     165             :     ros::Subscriber m_sub;
+     166             : 
+     167             :   protected:
+     168             :     std::string m_topic_name;
+     169             :     std::string m_node_name;
+     170             : 
+     171             :   protected:
+     172             :     bool m_got_data;   // whether any data was received
+     173             : 
+     174             :     mutable std::mutex m_new_data_mtx;
+     175             :     mutable std::condition_variable m_new_data_cv;
+     176             :     bool m_new_data;   // whether new data was received since last call to get_data
+     177             : 
+     178             :     bool m_used_data;  // whether get_data was successfully called at least once
+     179             : 
+     180             :   protected:
+     181             :     std::shared_ptr<mrs_lib::TimeoutManager> m_timeout_manager;
+     182             :     mrs_lib::TimeoutManager::timeout_id_t m_timeout_id;
+     183             : 
+     184             :   protected:
+     185             :     ros::Time m_latest_message_time;
+     186             :     typename MessageType::ConstPtr m_latest_message;
+     187             :     message_callback_t m_message_callback;
+     188             : 
+     189             :   private:
+     190             :     uint32_t m_queue_size;
+     191             :     ros::TransportHints m_transport_hints;
+     192             : 
+     193             :   protected:
+     194             :     /* default_timeout_callback() method //{ */
+     195           0 :     void default_timeout_callback(const std::string& topic_name, const ros::Time& last_msg)
+     196             :     {
+     197           0 :       const ros::Duration since_msg = (ros::Time::now() - last_msg);
+     198           0 :       const auto n_pubs = m_sub.getNumPublishers();
+     199           0 :       const std::string txt = "Did not receive any message from topic '" + topic_name + "' for " + std::to_string(since_msg.toSec()) + "s ("
+     200             :                               + std::to_string(n_pubs) + " publishers on this topic)";
+     201           0 :       if (m_node_name.empty())
+     202           0 :         ROS_WARN_STREAM(txt);
+     203             :       else
+     204           0 :         ROS_WARN_STREAM("[" << m_node_name << "]: " << txt);
+     205           0 :     }
+     206             :     //}
+     207             : 
+     208             :     /* process_new_message() method //{ */
+     209          20 :     void process_new_message(const typename MessageType::ConstPtr& msg)
+     210             :     {
+     211          20 :       m_latest_message_time = ros::Time::now();
+     212          20 :       m_latest_message = msg;
+     213             :       // If the message callback is registered, the new data will immediately be processed,
+     214             :       // so reset the flag. Otherwise, set the flag.
+     215          20 :       m_new_data = !m_message_callback;
+     216          20 :       m_got_data = true;
+     217          20 :       m_new_data_cv.notify_one();
+     218          20 :     }
+     219             :     //}
+     220             : 
+     221             :     /* data_callback() method //{ */
+     222           0 :     virtual void data_callback(const typename MessageType::ConstPtr& msg)
+     223             :     {
+     224             :       {
+     225           0 :         std::lock_guard lck(m_new_data_mtx);
+     226           0 :         if (m_timeout_manager)
+     227           0 :           m_timeout_manager->reset(m_timeout_id);
+     228           0 :         process_new_message(msg);
+     229             :       }
+     230             : 
+     231             :       // execute the callback after unlocking the mutex to enable multi-threaded callback execution
+     232           0 :       if (m_message_callback)
+     233           0 :         m_message_callback(msg);
+     234           0 :     }
+     235             :     //}
+     236             :   };
+     237             :   //}
+     238             : 
+     239             :   /* SubscribeHandler_threadsafe class //{ */
+     240             :   template <typename MessageType>
+     241             :   class SubscribeHandler<MessageType>::ImplThreadsafe : public SubscribeHandler<MessageType>::Impl
+     242             :   {
+     243             :   private:
+     244             :     using impl_class_t = SubscribeHandler<MessageType>::Impl;
+     245             : 
+     246             :   public:
+     247             :     using timeout_callback_t = typename impl_class_t::timeout_callback_t;
+     248             :     using message_callback_t = typename impl_class_t::message_callback_t;
+     249             : 
+     250             :     friend class SubscribeHandler<MessageType>;
+     251             : 
+     252             :   public:
+     253           1 :     ImplThreadsafe(const SubscribeHandlerOptions& options, const message_callback_t& message_callback = message_callback_t())
+     254           1 :         : impl_class_t::Impl(options, message_callback)
+     255             :     {
+     256           1 :     }
+     257             : 
+     258             :   public:
+     259       10000 :     virtual bool hasMsg() const override
+     260             :     {
+     261       20000 :       std::lock_guard lck(m_mtx);
+     262       20000 :       return impl_class_t::hasMsg();
+     263             :     }
+     264           0 :     virtual bool newMsg() const override
+     265             :     {
+     266           0 :       std::lock_guard lck(m_mtx);
+     267           0 :       return impl_class_t::newMsg();
+     268             :     }
+     269           0 :     virtual bool usedMsg() const override
+     270             :     {
+     271           0 :       std::lock_guard lck(m_mtx);
+     272           0 :       return impl_class_t::usedMsg();
+     273             :     }
+     274           0 :     virtual typename MessageType::ConstPtr getMsg() override
+     275             :     {
+     276           0 :       std::lock_guard lck(m_mtx);
+     277           0 :       return impl_class_t::getMsg();
+     278             :     }
+     279           0 :     virtual typename MessageType::ConstPtr peekMsg() const override
+     280             :     {
+     281           0 :       std::lock_guard lck(m_mtx);
+     282           0 :       return impl_class_t::peekMsg();
+     283             :     }
+     284           5 :     virtual ros::Time lastMsgTime() const override
+     285             :     {
+     286          10 :       std::lock_guard lck(m_mtx);
+     287          10 :       return impl_class_t::lastMsgTime();
+     288             :     };
+     289           0 :     virtual std::string topicName() const override
+     290             :     {
+     291           0 :       std::lock_guard lck(m_mtx);
+     292           0 :       return impl_class_t::topicName();
+     293             :     };
+     294           5 :     virtual void start() override
+     295             :     {
+     296          10 :       std::lock_guard lck(m_mtx);
+     297          10 :       return impl_class_t::start();
+     298             :     }
+     299           5 :     virtual void stop() override
+     300             :     {
+     301          10 :       std::lock_guard lck(m_mtx);
+     302          10 :       return impl_class_t::stop();
+     303             :     }
+     304             : 
+     305           2 :     virtual ~ImplThreadsafe() override = default;
+     306             : 
+     307             :   protected:
+     308          20 :     virtual void data_callback(const typename MessageType::ConstPtr& msg) override
+     309             :     {
+     310             :       {
+     311          40 :         std::scoped_lock lck(m_mtx, this->m_new_data_mtx);
+     312          20 :         if (this->m_timeout_manager)
+     313          20 :           this->m_timeout_manager->reset(this->m_timeout_id);
+     314          20 :         impl_class_t::process_new_message(msg);
+     315             :       }
+     316             : 
+     317             :       // execute the callback after unlocking the mutex to enable multi-threaded callback execution
+     318          20 :       if (this->m_message_callback)
+     319          20 :         impl_class_t::m_message_callback(msg);
+     320          20 :     }
+     321             : 
+     322             :   private:
+     323             :     mutable std::recursive_mutex m_mtx;
+     324             :   };
+     325             :   //}
+     326             : 
+     327             : }  // namespace mrs_lib
+     328             : 
+     329             : #endif  // SUBSCRIBE_HANDLER_HPP
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/timer.hpp.func-sort-c.html b/mrs_lib/include/mrs_lib/impl/timer.hpp.func-sort-c.html new file mode 100644 index 0000000000..7efe0491a9 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/timer.hpp.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/timer.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - timer.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:141687.5 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11ThreadTimerC2I5obj_tEERKN3ros10NodeHandleERKNS3_4RateEMT_FvRKNS3_10TimerEventEEPSA_bb8
_ZN7mrs_lib11ThreadTimerC2I5obj_tEERKN3ros10NodeHandleERKNS3_8DurationEMT_FvRKNS3_10TimerEventEEPSA_bb8
_ZN7mrs_lib8ROSTimerC2I5obj_tEERKN3ros10NodeHandleERKNS3_4RateEMT_FvRKNS3_10TimerEventEEPSA_bb8
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/timer.hpp.func.html b/mrs_lib/include/mrs_lib/impl/timer.hpp.func.html new file mode 100644 index 0000000000..f30380f1b6 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/timer.hpp.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/timer.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - timer.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:141687.5 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11ThreadTimerC2I5obj_tEERKN3ros10NodeHandleERKNS3_4RateEMT_FvRKNS3_10TimerEventEEPSA_bb8
_ZN7mrs_lib11ThreadTimerC2I5obj_tEERKN3ros10NodeHandleERKNS3_8DurationEMT_FvRKNS3_10TimerEventEEPSA_bb8
_ZN7mrs_lib8ROSTimerC2I5obj_tEERKN3ros10NodeHandleERKNS3_4RateEMT_FvRKNS3_10TimerEventEEPSA_bb8
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/timer.hpp.gcov.html b/mrs_lib/include/mrs_lib/impl/timer.hpp.gcov.html new file mode 100644 index 0000000000..c7e70ebb4c --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/timer.hpp.gcov.html @@ -0,0 +1,171 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/timer.hpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - timer.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:141687.5 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef MRS_TIMER_HPP
+       2             : #define MRS_TIMER_HPP
+       3             : 
+       4             : // | ------------------------ ROSTimer ------------------------ |
+       5             : 
+       6             : /* ROSTimer constructors //{ */
+       7             : 
+       8             : // duration + oneshot + autostart
+       9             : #include <chrono>
+      10             : #include <mutex>
+      11             : template <class ObjectType>
+      12             : ROSTimer::ROSTimer(const ros::NodeHandle& nh, const ros::Duration& duration, void (ObjectType::*const callback)(const ros::TimerEvent&),
+      13             :                    ObjectType* const obj, const bool oneshot, const bool autostart) {
+      14             : 
+      15             :   this->timer_ = std::make_unique<ros::Timer>(nh.createTimer(duration, callback, obj, oneshot, autostart));
+      16             : }
+      17             : 
+      18             : // rate + oneshot + autostart
+      19             : template <class ObjectType>
+      20           8 : ROSTimer::ROSTimer(const ros::NodeHandle& nh, const ros::Rate& rate, void (ObjectType::*const callback)(const ros::TimerEvent&), ObjectType* const obj,
+      21           8 :                    const bool oneshot, const bool autostart) {
+      22             : 
+      23           8 :   this->timer_ = std::make_unique<ros::Timer>(nh.createTimer(rate, callback, obj, oneshot, autostart));
+      24           8 : }
+      25             : 
+      26             : //}
+      27             : 
+      28             : // | ----------------------- ThreadTimer ---------------------- |
+      29             : 
+      30             : /* class ThreadTimer::Impl //{ */
+      31             : 
+      32             : class ThreadTimer::Impl {
+      33             : public:
+      34             :   Impl(const std::function<void(const ros::TimerEvent&)>& callback, const ros::Duration& delay_dur, const bool oneshot);
+      35             :   ~Impl();
+      36             : 
+      37             :   void start();
+      38             :   void stop();
+      39             :   void setPeriod(const ros::Duration& duration, const bool reset = true);
+      40             : 
+      41             :   friend class ThreadTimer;
+      42             : 
+      43             :   // to keep rule of five since we have a custom destructor
+      44             :   Impl(const Impl&) = delete;
+      45             :   Impl(Impl&&) = delete;
+      46             :   Impl& operator=(const Impl&) = delete;
+      47             :   Impl& operator=(Impl&&) = delete;
+      48             : 
+      49             : private:
+      50             :   std::thread thread_;
+      51             :   std::function<void(const ros::TimerEvent&)> callback_;
+      52             : 
+      53             :   bool oneshot_;
+      54             : 
+      55             :   bool breakableSleep(const ros::Time& until);
+      56             :   void threadFcn();
+      57             : 
+      58             :   std::mutex mutex_wakeup_;
+      59             :   std::condition_variable wakeup_cond_;
+      60             :   std::recursive_mutex mutex_state_;
+      61             :   bool running_;
+      62             :   ros::Duration delay_dur_;
+      63             :   bool ending_;
+      64             :   ros::Time next_expected_;
+      65             :   ros::Time last_expected_;
+      66             :   ros::Time last_real_;
+      67             : 
+      68             : };
+      69             : 
+      70             : //}
+      71             : 
+      72             : /* ThreadTimer constructors and destructors//{ */
+      73             : 
+      74             : template <class ObjectType>
+      75           8 : ThreadTimer::ThreadTimer([[maybe_unused]] const ros::NodeHandle& nh, const ros::Rate& rate, void (ObjectType::*const callback)(const ros::TimerEvent&),
+      76             :                          ObjectType* const obj, const bool oneshot, const bool autostart)
+      77           8 :   : ThreadTimer(nh, rate.expectedCycleTime(), callback, obj, oneshot, autostart)
+      78             : {
+      79           8 : }
+      80             : 
+      81             : template <class ObjectType>
+      82           8 : ThreadTimer::ThreadTimer([[maybe_unused]] const ros::NodeHandle& nh, const ros::Duration& duration,
+      83           8 :                          void (ObjectType::*const callback)(const ros::TimerEvent&), ObjectType* const obj, bool oneshot, const bool autostart) 
+      84             : {
+      85           8 :   const auto cbk = std::bind(callback, obj, std::placeholders::_1);
+      86           8 :   if (duration == ros::Duration(0))
+      87           0 :     oneshot = true;
+      88           8 :   this->impl_ = std::make_unique<Impl>(cbk, duration, oneshot);
+      89           8 :   if (autostart)
+      90           0 :     this->impl_->start();
+      91           8 : }
+      92             : 
+      93             : //}
+      94             : 
+      95             : #endif  // MRS_TIMER_HPP
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/transformer.hpp.func-sort-c.html b/mrs_lib/include/mrs_lib/impl/transformer.hpp.func-sort-c.html new file mode 100644 index 0000000000..f5e236d8c4 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/transformer.hpp.func-sort-c.html @@ -0,0 +1,220 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/transformer.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - transformer.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:446468.8 %
Date:2023-11-29 14:09:54Functions:233762.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11Transformer11doTransformIN5Eigen10QuaternionIdLi0EEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs11Quaternion_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs12PoseStamped_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs13PointStamped_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs6Point_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs8Vector3_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN2cv7Point3_IdEEEET_RKS5_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN5Eigen10QuaternionIdLi0EEEEET_RKS5_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIT_ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS7_SG_RKN3ros4TimeE0
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer9getHeaderIN13geometry_msgs12PoseStamped_ISaIvEEEEEN8std_msgs7Header_IS4_EERKT_0
_ZN7mrs_lib11Transformer9getHeaderIN8mrs_msgs17ReferenceStamped_ISaIvEEEEEN8std_msgs7Header_IS4_EERKT_0
_ZN7mrs_lib11Transformer9setHeaderIN13geometry_msgs12PoseStamped_ISaIvEEEEEvRT_RKN8std_msgs7Header_IS4_EE0
_ZN7mrs_lib11Transformer9setHeaderIN13geometry_msgs13PointStamped_ISaIvEEEEEvRT_RKN8std_msgs7Header_IS4_EE0
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE1
_ZN7mrs_lib11Transformer11doTransformIN2cv7Point3_IdEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_1
_ZN7mrs_lib11Transformer13transformImplIN2cv7Point3_IdEEEESt8optionalIT_ERKN13geometry_msgs17TransformStamped_ISaIvEEERKS6_1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS7_SG_RKN3ros4TimeE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS7_SG_RKN3ros4TimeE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer9getHeaderIN13geometry_msgs13PointStamped_ISaIvEEEEEN8std_msgs7Header_IS4_EERKT_1
_ZN7mrs_lib11Transformer9transformIN2cv7Point3_IdEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer13transformImplIN5Eigen10QuaternionIdLi0EEEEESt8optionalIT_ERKN13geometry_msgs17TransformStamped_ISaIvEEERKS6_2
_ZN7mrs_lib11Transformer9transformIN5Eigen10QuaternionIdLi0EEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE2
_ZN7mrs_lib11Transformer9transformIN13geometry_msgs6Point_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE4
_ZN7mrs_lib11Transformer9transformIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE5
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE6
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs12PoseStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE6
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_6
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs12PoseStamped_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_6
_ZN7mrs_lib11Transformer9transformIN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE6
_ZN7mrs_lib11Transformer9transformIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKN13geometry_msgs17TransformStamped_IS4_EE6
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs6Point_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE16
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs6Point_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_16
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs8Vector3_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE18
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs8Vector3_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_18
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/transformer.hpp.func.html b/mrs_lib/include/mrs_lib/impl/transformer.hpp.func.html new file mode 100644 index 0000000000..fcad264828 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/transformer.hpp.func.html @@ -0,0 +1,220 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/transformer.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - transformer.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:446468.8 %
Date:2023-11-29 14:09:54Functions:233762.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE6
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs12PoseStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE6
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE1
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs6Point_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE16
_ZN7mrs_lib11Transformer11doTransformIN13geometry_msgs8Vector3_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE18
_ZN7mrs_lib11Transformer11doTransformIN2cv7Point3_IdEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer11doTransformIN5Eigen10QuaternionIdLi0EEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE0
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_6
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs12PoseStamped_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_6
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_1
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs6Point_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_16
_ZN7mrs_lib11Transformer13transformImplIN13geometry_msgs8Vector3_ISaIvEEEEESt8optionalIT_ERKNS2_17TransformStamped_IS4_EERKS7_18
_ZN7mrs_lib11Transformer13transformImplIN2cv7Point3_IdEEEESt8optionalIT_ERKN13geometry_msgs17TransformStamped_ISaIvEEERKS6_1
_ZN7mrs_lib11Transformer13transformImplIN5Eigen10QuaternionIdLi0EEEEESt8optionalIT_ERKN13geometry_msgs17TransformStamped_ISaIvEEERKS6_2
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs11Quaternion_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs12PoseStamped_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs13PointStamped_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs6Point_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN13geometry_msgs8Vector3_ISaIvEEEEET_RKS6_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN2cv7Point3_IdEEEET_RKS5_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15copyChangeFrameIN5Eigen10QuaternionIdLi0EEEEET_RKS5_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS7_SG_RKN3ros4TimeE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS7_SG_RKN3ros4TimeE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIT_ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS7_SG_RKN3ros4TimeE0
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer9getHeaderIN13geometry_msgs12PoseStamped_ISaIvEEEEEN8std_msgs7Header_IS4_EERKT_0
_ZN7mrs_lib11Transformer9getHeaderIN13geometry_msgs13PointStamped_ISaIvEEEEEN8std_msgs7Header_IS4_EERKT_1
_ZN7mrs_lib11Transformer9getHeaderIN8mrs_msgs17ReferenceStamped_ISaIvEEEEEN8std_msgs7Header_IS4_EERKT_0
_ZN7mrs_lib11Transformer9setHeaderIN13geometry_msgs12PoseStamped_ISaIvEEEEEvRT_RKN8std_msgs7Header_IS4_EE0
_ZN7mrs_lib11Transformer9setHeaderIN13geometry_msgs13PointStamped_ISaIvEEEEEvRT_RKN8std_msgs7Header_IS4_EE0
_ZN7mrs_lib11Transformer9transformIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE5
_ZN7mrs_lib11Transformer9transformIN13geometry_msgs6Point_ISaIvEEEEESt8optionalIT_ERKS7_RKNS2_17TransformStamped_IS4_EE4
_ZN7mrs_lib11Transformer9transformIN2cv7Point3_IdEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer9transformIN5Eigen10QuaternionIdLi0EEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE2
_ZN7mrs_lib11Transformer9transformIN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEEESt8optionalIT_ERKS6_RKN13geometry_msgs17TransformStamped_ISaIvEEE6
_ZN7mrs_lib11Transformer9transformIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIT_ERKS7_RKN13geometry_msgs17TransformStamped_IS4_EE6
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/transformer.hpp.gcov.html b/mrs_lib/include/mrs_lib/impl/transformer.hpp.gcov.html new file mode 100644 index 0000000000..4ac2f99061 --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/transformer.hpp.gcov.html @@ -0,0 +1,272 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/transformer.hpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - transformer.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:446468.8 %
Date:2023-11-29 14:09:54Functions:233762.2 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef TRANSFORMER_HPP
+       2             : #define TRANSFORMER_HPP
+       3             : 
+       4             : // clang: MatousFormat
+       5             : 
+       6             : namespace mrs_lib
+       7             : {
+       8             : 
+       9             :   // | --------------------- helper methods --------------------- |
+      10             : 
+      11             :   /* getHeader() overloads for different message types (pointers, pointclouds etc) //{ */
+      12             : 
+      13             :   template <typename msg_t>
+      14           1 :   std_msgs::Header Transformer::getHeader(const msg_t& msg)
+      15             :   {
+      16           1 :     return msg.header;
+      17             :   }
+      18             : 
+      19             :   template <typename pt_t>
+      20             :   std_msgs::Header Transformer::getHeader(const pcl::PointCloud<pt_t>& cloud)
+      21             :   {
+      22             :     std_msgs::Header ret;
+      23             :     pcl_conversions::fromPCL(cloud.header, ret);
+      24             :     return ret;
+      25             :   }
+      26             : 
+      27             :   //}
+      28             : 
+      29             :   /* setHeader() overloads for different message types (pointers, pointclouds etc) //{ */
+      30             : 
+      31             :   template <typename msg_t>
+      32           0 :   void Transformer::setHeader(msg_t& msg, const std_msgs::Header& header)
+      33             :   {
+      34           0 :     msg.header = header;
+      35           0 :   }
+      36             : 
+      37             :   template <typename pt_t>
+      38             :   void Transformer::setHeader(pcl::PointCloud<pt_t>& cloud, const std_msgs::Header& header)
+      39             :   {
+      40             :     pcl_conversions::toPCL(header, cloud.header);
+      41             :   }
+      42             : 
+      43             :   //}
+      44             : 
+      45             :   /* copyChangeFrame() helper function //{ */
+      46             : 
+      47             :   template <typename T>
+      48           0 :   T Transformer::copyChangeFrame(const T& what, const std::string& frame_id)
+      49             :   {
+      50           0 :     T ret = what;
+      51             :     if constexpr (has_header_member_v<T>)
+      52             :     {
+      53           0 :       std_msgs::Header new_header = getHeader(what);
+      54           0 :       new_header.frame_id = frame_id;
+      55           0 :       setHeader(ret, new_header);
+      56             :     }
+      57           0 :     return ret;
+      58             :   }
+      59             : 
+      60             :   //}
+      61             : 
+      62             :   /* transformImpl() //{ */
+      63             : 
+      64             :   template <class T>
+      65          50 :   std::optional<T> Transformer::transformImpl(const geometry_msgs::TransformStamped& tf, const T& what)
+      66             :   {
+      67         100 :     const std::string from_frame = frame_from(tf);
+      68         100 :     const std::string to_frame = frame_to(tf);
+      69             : 
+      70          50 :     if (from_frame == to_frame)
+      71           0 :       return copyChangeFrame(what, from_frame);
+      72             : 
+      73         100 :     const std::string latlon_frame_name = resolveFrameImpl(LATLON_ORIGIN);
+      74             : 
+      75             :     // First, check if the transformation is from/to the latlon frame
+      76             :     // if conversion between UVM and LatLon coordinates is defined for this message, it may be resolved
+      77             :     if constexpr (UTMLL_exists_v<Transformer, T>)
+      78             :     {
+      79             :       // check for transformation from LAT-LON GPS
+      80          23 :       if (from_frame == latlon_frame_name)
+      81             :       {
+      82           2 :         const std::optional<T> tmp = LLtoUTM(what, getFramePrefix(from_frame));
+      83           2 :         if (!tmp.has_value())
+      84           0 :           return std::nullopt;
+      85           2 :         return doTransform(tmp.value(), tf);
+      86             :       }
+      87             :       // check for transformation to LAT-LON GPS
+      88          21 :       else if (to_frame == latlon_frame_name)
+      89             :       {
+      90           2 :         const std::optional<T> tmp = doTransform(what, tf);
+      91           2 :         if (!tmp.has_value())
+      92           0 :           return std::nullopt;
+      93           2 :         return UTMtoLL(tmp.value(), getFramePrefix(to_frame));
+      94             :       }
+      95             :     }
+      96             :     else
+      97             :     {
+      98             :       // by default, transformation from/to LATLON is undefined, so return nullopt if it's attempted
+      99          27 :       if (from_frame == latlon_frame_name || to_frame == latlon_frame_name)
+     100             :       {
+     101           2 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[" << node_name_ << "]: Transformer: cannot transform message of this type (" << typeid(T).name() << ") to/from latitude/longitude coordinates!");
+     102           2 :         return std::nullopt;
+     103             :       }
+     104             :     }
+     105             : 
+     106             :     // otherwise it's just an ol' borin' transformation
+     107          44 :     return doTransform(what, tf);
+     108             :   }
+     109             : 
+     110             :   //}
+     111             : 
+     112             :   /* doTransform() //{ */
+     113             : 
+     114             :   template <class T>
+     115          48 :   std::optional<T> Transformer::doTransform(const T& what, const geometry_msgs::TransformStamped& tf)
+     116             :   {
+     117             :     try
+     118             :     {
+     119          55 :       T result;
+     120          48 :       tf2::doTransform(what, result, tf);
+     121          48 :       return result;
+     122             :     }
+     123           0 :     catch (tf2::TransformException& ex)
+     124             :     {
+     125           0 :       ROS_WARN_THROTTLE(1.0, "[%s]: Transformer: Error during transform from \"%s\" frame to \"%s\" frame.\n\tMSG: %s", node_name_.c_str(), frame_from(tf).c_str(),
+     126             :                         frame_to(tf).c_str(), ex.what());
+     127           0 :       return std::nullopt;
+     128             :     }
+     129             :   }
+     130             : 
+     131             :   //}
+     132             : 
+     133             :   // | ------------------ user-callable methods ----------------- |
+     134             : 
+     135             :   /* transformSingle() //{ */
+     136             : 
+     137             :   template <class T>
+     138           1 :   std::optional<T> Transformer::transformSingle(const T& what, const std::string& to_frame_raw)
+     139             :   {
+     140           2 :     const std_msgs::Header orig_header = getHeader(what);
+     141           2 :     return transformSingle(orig_header.frame_id, what, to_frame_raw, orig_header.stamp);
+     142             :   }
+     143             : 
+     144             :   template <class T>
+     145           2 :   std::optional<T> Transformer::transformSingle(const std::string& from_frame_raw, const T& what, const std::string& to_frame_raw, const ros::Time& time_stamp)
+     146             :   {
+     147           4 :     std::scoped_lock lck(mutex_);
+     148             : 
+     149           2 :     if (!initialized_)
+     150             :     {
+     151           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot transform, not initialized", node_name_.c_str());
+     152           0 :       return std::nullopt;
+     153             :     }
+     154             : 
+     155           4 :     const std::string from_frame = resolveFrameImpl(from_frame_raw);
+     156           4 :     const std::string to_frame = resolveFrameImpl(to_frame_raw);
+     157           4 :     const std::string latlon_frame = resolveFrameImpl(LATLON_ORIGIN);
+     158             : 
+     159             :     // get the transform
+     160           4 :     const auto tf_opt = getTransformImpl(from_frame, to_frame, time_stamp, latlon_frame);
+     161           2 :     if (!tf_opt.has_value())
+     162           0 :       return std::nullopt;
+     163           2 :     const geometry_msgs::TransformStamped& tf = tf_opt.value();
+     164             : 
+     165             :     // do the transformation
+     166           4 :     const geometry_msgs::TransformStamped tf_resolved = create_transform(from_frame, to_frame, tf.header.stamp, tf.transform);
+     167           2 :     return transformImpl(tf_resolved, what);
+     168             :   }
+     169             : 
+     170             :   //}
+     171             : 
+     172             :   /* transform() //{ */
+     173             : 
+     174             :   template <class T>
+     175          24 :   std::optional<T> Transformer::transform(const T& what, const geometry_msgs::TransformStamped& tf)
+     176             :   {
+     177          48 :     std::scoped_lock lck(mutex_);
+     178             : 
+     179          24 :     if (!initialized_)
+     180             :     {
+     181           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot transform, not initialized", node_name_.c_str());
+     182           0 :       return std::nullopt;
+     183             :     }
+     184             : 
+     185          48 :     const std::string from_frame = resolveFrameImpl(frame_from(tf));
+     186          48 :     const std::string to_frame = resolveFrameImpl(frame_to(tf));
+     187          48 :     const geometry_msgs::TransformStamped tf_resolved = create_transform(from_frame, to_frame, tf.header.stamp, tf.transform);
+     188             : 
+     189          24 :     return transformImpl(tf_resolved, what);
+     190             :   }
+     191             : 
+     192             :   /* //} */
+     193             : 
+     194             : }
+     195             : 
+     196             : #endif // TRANSFORMER_HPP
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/ukf.hpp.func-sort-c.html b/mrs_lib/include/mrs_lib/impl/ukf.hpp.func-sort-c.html new file mode 100644 index 0000000000..bef7f6f4ba --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/ukf.hpp.func-sort-c.html @@ -0,0 +1,120 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/ukf.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - ukf.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:7710474.0 %
Date:2023-11-29 14:09:54Functions:81266.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib3UKFILi4ELi1ELi2EE12setConstantsEddd0
_ZN7mrs_lib3UKFILi4ELi1ELi2EE18setTransitionModelERKSt8functionIFN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKS5_RKNS4_IdLi1ELi1ELi0ELi1ELi1EEEdEE0
_ZN7mrs_lib3UKFILi4ELi1ELi2EE19setObservationModelERKSt8functionIFN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS4_IdLi4ELi1ELi0ELi4ELi1EEEEE0
_ZN7mrs_lib3UKFILi4ELi1ELi2EEC2Ev0
_ZN7mrs_lib3UKFILi4ELi1ELi2EE14computeWeightsEv1
_ZN7mrs_lib3UKFILi4ELi1ELi2EEC2ERKSt8functionIFN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKS5_RKNS4_IdLi1ELi1ELi0ELi1ELi1EEEdEERKS2_IFNS4_IdLi2ELi1ELi0ELi2ELi1EEES7_EEddd1
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE14computeInverseERKN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEE100
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE17computeKalmanGainERKN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKNS3_IdLi2ELi1ELi0ELi2ELi1EEERKNS3_IdLi4ELi2ELi0ELi4ELi2EEERKNS3_IdLi2ELi2ELi0ELi2ELi2EEE100
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE7correctERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEE100
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE7predictERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi4ELi4ELi0ELi4ELi4EEEd100
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE13computePaSqrtERKN5Eigen6MatrixIdLi4ELi4ELi0ELi4ELi4EEE200
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE13computeSigmasERKN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKNS3_IdLi4ELi4ELi0ELi4ELi4EEE200
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/ukf.hpp.func.html b/mrs_lib/include/mrs_lib/impl/ukf.hpp.func.html new file mode 100644 index 0000000000..90fe6a5c7f --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/ukf.hpp.func.html @@ -0,0 +1,120 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/ukf.hpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - ukf.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:7710474.0 %
Date:2023-11-29 14:09:54Functions:81266.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib3UKFILi4ELi1ELi2EE12setConstantsEddd0
_ZN7mrs_lib3UKFILi4ELi1ELi2EE14computeWeightsEv1
_ZN7mrs_lib3UKFILi4ELi1ELi2EE18setTransitionModelERKSt8functionIFN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKS5_RKNS4_IdLi1ELi1ELi0ELi1ELi1EEEdEE0
_ZN7mrs_lib3UKFILi4ELi1ELi2EE19setObservationModelERKSt8functionIFN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS4_IdLi4ELi1ELi0ELi4ELi1EEEEE0
_ZN7mrs_lib3UKFILi4ELi1ELi2EEC2ERKSt8functionIFN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKS5_RKNS4_IdLi1ELi1ELi0ELi1ELi1EEEdEERKS2_IFNS4_IdLi2ELi1ELi0ELi2ELi1EEES7_EEddd1
_ZN7mrs_lib3UKFILi4ELi1ELi2EEC2Ev0
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE13computePaSqrtERKN5Eigen6MatrixIdLi4ELi4ELi0ELi4ELi4EEE200
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE13computeSigmasERKN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKNS3_IdLi4ELi4ELi0ELi4ELi4EEE200
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE14computeInverseERKN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEE100
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE17computeKalmanGainERKN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEERKNS3_IdLi2ELi1ELi0ELi2ELi1EEERKNS3_IdLi4ELi2ELi0ELi4ELi2EEERKNS3_IdLi2ELi2ELi0ELi2ELi2EEE100
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE7correctERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEE100
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE7predictERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi4ELi4ELi0ELi4ELi4EEEd100
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/impl/ukf.hpp.gcov.html b/mrs_lib/include/mrs_lib/impl/ukf.hpp.gcov.html new file mode 100644 index 0000000000..c0298a7a3e --- /dev/null +++ b/mrs_lib/include/mrs_lib/impl/ukf.hpp.gcov.html @@ -0,0 +1,356 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/impl/ukf.hpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib/impl - ukf.hpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:7710474.0 %
Date:2023-11-29 14:09:54Functions:81266.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : 
+       3             : #ifndef UKF_HPP
+       4             : #define UKF_HPP
+       5             : 
+       6             : /**  \file
+       7             :      \brief Implements UKF - a class implementing the Unscented Kalman Filter.
+       8             :      \author Tomáš Báča - bacatoma@fel.cvut.cz (original implementation)
+       9             :      \author Matouš Vrba - vrbamato@fel.cvut.cz (rewrite, documentation)
+      10             :  */
+      11             : 
+      12             : #include <ros/ros.h>
+      13             : #include <mrs_lib/ukf.h>
+      14             : 
+      15             : namespace mrs_lib
+      16             : {
+      17             :   /* constructor //{ */
+      18             : 
+      19             :   template <int n_states, int n_inputs, int n_measurements>
+      20           0 :   UKF<n_states, n_inputs, n_measurements>::UKF()
+      21             :   {
+      22           0 :   }
+      23             : 
+      24             :   template <int n_states, int n_inputs, int n_measurements>
+      25           1 :   UKF<n_states, n_inputs, n_measurements>::UKF(const transition_model_t& transition_model, const observation_model_t& observation_model, const double alpha, const double kappa, const double beta)
+      26           1 :     : m_alpha(alpha), m_kappa(kappa), m_beta(beta), m_Wm(W_t::Zero()), m_Wc(W_t::Zero()), m_transition_model(transition_model), m_observation_model(observation_model)
+      27             :   {
+      28           1 :     assert(alpha > 0.0);
+      29           1 :     computeWeights();
+      30           1 :   }
+      31             : 
+      32             :   //}
+      33             : 
+      34             :   /* computeWeights() //{ */
+      35             : 
+      36             :   template <int n_states, int n_inputs, int n_measurements>
+      37           1 :   void UKF<n_states, n_inputs, n_measurements>::computeWeights()
+      38             :   {
+      39             :     // initialize lambda
+      40             :     /* m_lambda = double(n) * (m_alpha * m_alpha - 1.0); */
+      41           1 :     m_lambda = m_alpha*m_alpha*(double(n) + m_kappa) - double(n);
+      42             : 
+      43             :     // initialize first terms of the weights
+      44           1 :     m_Wm(0) = m_lambda / (double(n) + m_lambda);
+      45           1 :     m_Wc(0) = m_Wm(0) + (1.0 - m_alpha*m_alpha + m_beta);
+      46             : 
+      47             :     // initialize the rest of the weights
+      48           9 :     for (int i = 1; i < w; i++)
+      49             :     {
+      50           8 :       m_Wm(i) = (1.0 - m_Wm(0))/(w - 1.0);
+      51           8 :       m_Wc(i) = m_Wm(i);
+      52             :     }
+      53           1 :   }
+      54             : 
+      55             :   //}
+      56             : 
+      57             :   /* setConstants() //{ */
+      58             : 
+      59             :   template <int n_states, int n_inputs, int n_measurements>
+      60             :   // update the UKF constants
+      61           0 :   void UKF<n_states, n_inputs, n_measurements>::setConstants(const double alpha, const double kappa, const double beta)
+      62             :   {
+      63           0 :     m_alpha = alpha;
+      64           0 :     m_kappa = kappa;
+      65           0 :     m_beta  = beta;
+      66             : 
+      67           0 :     computeWeights();
+      68           0 :   }
+      69             : 
+      70             :   //}
+      71             : 
+      72             :     /* setTransitionModel() method //{ */
+      73             : 
+      74             :     template <int n_states, int n_inputs, int n_measurements>
+      75           0 :     void UKF<n_states, n_inputs, n_measurements>::setTransitionModel(const transition_model_t& transition_model)
+      76             :     {
+      77           0 :       m_transition_model = transition_model;
+      78           0 :     }
+      79             : 
+      80             :     //}
+      81             : 
+      82             :     /* setObservationModel() method //{ */
+      83             : 
+      84             :     template <int n_states, int n_inputs, int n_measurements>
+      85           0 :     void UKF<n_states, n_inputs, n_measurements>::setObservationModel(const observation_model_t& observation_model)
+      86             :     {
+      87           0 :       m_observation_model = observation_model;
+      88           0 :     }
+      89             : 
+      90             :     //}
+      91             : 
+      92             :   /* computePaSqrt() method //{ */
+      93             :   template <int n_states, int n_inputs, int n_measurements>
+      94         200 :   typename UKF<n_states, n_inputs, n_measurements>::P_t UKF<n_states, n_inputs, n_measurements>::computePaSqrt(const P_t& P) const
+      95             :   {
+      96             :     // calculate the square root of the covariance matrix
+      97         200 :     const P_t Pa = (double(n) + m_lambda)*P;
+      98             : 
+      99             :     /* Eigen::SelfAdjointEigenSolver<P_t> es(Pa); */
+     100         200 :     Eigen::LLT<P_t> llt(Pa);
+     101         200 :     if (llt.info() != Eigen::Success)
+     102             :     {
+     103           0 :       P_t tmp = Pa + (double(n) + m_lambda)*1e-9*P_t::Identity();
+     104           0 :       llt.compute(tmp);
+     105           0 :       if (llt.info() != Eigen::Success)
+     106             :       {
+     107           0 :         ROS_WARN("UKF: taking the square root of covariance during sigma point generation failed.");
+     108           0 :         throw square_root_exception();
+     109             :       }
+     110             :     }
+     111             : 
+     112         200 :     const P_t Pa_sqrt = llt.matrixL();
+     113         400 :     return Pa_sqrt;
+     114             :   }
+     115             :   //}
+     116             : 
+     117             :   /* computeInverse() method //{ */
+     118             :   template <int n_states, int n_inputs, int n_measurements>
+     119         100 :   typename UKF<n_states, n_inputs, n_measurements>::Pzz_t UKF<n_states, n_inputs, n_measurements>::computeInverse(const Pzz_t& Pzz) const
+     120             :   {
+     121         100 :     Eigen::ColPivHouseholderQR<Pzz_t> qr(Pzz);
+     122         100 :     if (!qr.isInvertible())
+     123             :     {
+     124             :       // add some stuff to the tmp matrix diagonal to make it invertible
+     125           0 :       Pzz_t tmp = Pzz + 1e-9*Pzz_t::Identity(Pzz.rows(), Pzz.cols());
+     126           0 :       qr.compute(tmp);
+     127           0 :       if (!qr.isInvertible())
+     128             :       {
+     129             :         // never managed to make this happen except for explicitly putting NaNs in the input
+     130           0 :         ROS_ERROR("UKF: could not compute matrix inversion!!! Fix your covariances (the measurement's is probably too low...)");
+     131           0 :         throw inverse_exception();
+     132             :       }
+     133           0 :       ROS_WARN("UKF: artificially inflating matrix for inverse computation! Check your covariances (the measurement's might be too low...)");
+     134             :     }
+     135         100 :     Pzz_t ret = qr.inverse();
+     136         200 :     return ret;
+     137             :   }
+     138             :   //}
+     139             : 
+     140             :   /* computeKalmanGain() method //{ */
+     141             :   template <int n_states, int n_inputs, int n_measurements>
+     142         100 :   typename UKF<n_states, n_inputs, n_measurements>::K_t UKF<n_states, n_inputs, n_measurements>::computeKalmanGain([[maybe_unused]] const x_t& x, [[maybe_unused]] const z_t& inn, const K_t& Pxz, const Pzz_t& Pzz) const
+     143             :   {
+     144         100 :     const Pzz_t Pzz_inv = computeInverse(Pzz);
+     145         100 :     const K_t K = Pxz * Pzz_inv;
+     146         200 :     return K;
+     147             :   }
+     148             :   //}
+     149             : 
+     150             :   /* computeSigmas() method //{ */
+     151             :   template <int n_states, int n_inputs, int n_measurements>
+     152         200 :   typename UKF<n_states, n_inputs, n_measurements>::X_t UKF<n_states, n_inputs, n_measurements>::computeSigmas(const x_t& x, const P_t& P) const
+     153             :   {
+     154             :     // calculate sigma points
+     155             :     // fill in the middle of the elipsoid
+     156         200 :     X_t S;
+     157         200 :     S.col(0) = x;
+     158             : 
+     159         200 :     const P_t P_sqrt = computePaSqrt(P);
+     160         200 :     const auto xrep = x.replicate(1, n);
+     161             : 
+     162             :     // positive sigma points
+     163         200 :     S.template block<n, n>(0, 1) = xrep + P_sqrt;
+     164             : 
+     165             :     // negative sigma points
+     166         200 :     S.template block<n, n>(0, n+1) = xrep - P_sqrt;
+     167             : 
+     168             :     /* std::cout << "x: " << std::endl << x << std::endl; */
+     169             :     /* std::cout << "S rowmean: " << std::endl << S.rowwise().mean() << std::endl; */
+     170             : 
+     171         400 :     return S;
+     172             :   }
+     173             :   //}
+     174             : 
+     175             :   /* predict() method //{ */
+     176             : 
+     177             :   template <int n_states, int n_inputs, int n_measurements>
+     178         100 :   typename UKF<n_states, n_inputs, n_measurements>::statecov_t UKF<n_states, n_inputs, n_measurements>::predict(const statecov_t& sc, const u_t& u, const Q_t& Q, double dt) const
+     179             :   {
+     180         100 :     const auto& x = sc.x;
+     181         100 :     const auto& P = sc.P;
+     182         100 :     statecov_t ret;
+     183             : 
+     184         100 :     const X_t S = computeSigmas(x, P);
+     185             : 
+     186             :     // propagate sigmas through the transition model
+     187         100 :     X_t X;
+     188        1000 :     for (int i = 0; i < w; i++)
+     189             :     {
+     190         900 :       X.col(i) = m_transition_model(S.col(i), u, dt);
+     191             :     }
+     192             : 
+     193             :     /* std::cout << "x: " << std::endl << x << std::endl; */
+     194             :     /* std::cout << "X rowmean: " << std::endl << X.rowwise().mean() << std::endl; */
+     195             :     /* std::cout << "m_Wm sum: " << m_Wm.sum() << std::endl; */
+     196             : 
+     197             :     // recompute the state vector
+     198         100 :     ret.x = x_t::Zero();
+     199        1000 :     for (int i = 0; i < w; i++)
+     200             :     {
+     201             :       //TODO: WHY DOES THIS SHIT WORK IF I SUBSTITUTE m_Wm(i) FOR 1.0/w ??
+     202         900 :       x_t tmp = 1.0/w * X.col(i);
+     203             :       /* x_t tmp = m_Wm(i) * X.col(i); */
+     204         900 :       ret.x += tmp;
+     205             :     }
+     206             : 
+     207             :     // recompute the covariance
+     208         100 :     ret.P = P_t::Zero();
+     209        1000 :     for (int i = 0; i < w; i++)
+     210             :     {
+     211         900 :       ret.P += m_Wc(i) * (X.col(i) - ret.x) * (X.col(i) - ret.x).transpose();
+     212             :     }
+     213         100 :     ret.P += Q;
+     214             : 
+     215         200 :     return ret;
+     216             :   }
+     217             : 
+     218             :   //}
+     219             : 
+     220             :   /* correct() method //{ */
+     221             : 
+     222             :   template <int n_states, int n_inputs, int n_measurements>
+     223         100 :   typename UKF<n_states, n_inputs, n_measurements>::statecov_t UKF<n_states, n_inputs, n_measurements>::correct(const statecov_t& sc, const z_t& z, const R_t& R) const
+     224             :   {
+     225         100 :     const auto& x = sc.x;
+     226         100 :     const auto& P = sc.P;
+     227         100 :     const X_t S = computeSigmas(x, P);
+     228             : 
+     229             :     // propagate sigmas through the observation model
+     230         100 :     Z_t Z_exp(z.rows(), w);
+     231        1000 :     for (int i = 0; i < w; i++)
+     232             :     {
+     233         900 :       Z_exp.col(i) = m_observation_model(S.col(i));
+     234             :     }
+     235             : 
+     236             :     // compute expected measurement
+     237         100 :     z_t z_exp = z_t::Zero(z.rows());
+     238        1000 :     for (int i = 0; i < w; i++)
+     239             :     {
+     240         900 :       z_exp += m_Wm(i) * Z_exp.col(i);
+     241             :     }
+     242             : 
+     243             :     // compute the covariance of measurement
+     244         100 :     Pzz_t Pzz = Pzz_t::Zero(z.rows(), z.rows());
+     245        1000 :     for (int i = 0; i < w; i++)
+     246             :     {
+     247         900 :       Pzz += m_Wc(i) * (Z_exp.col(i) - z_exp) * (Z_exp.col(i) - z_exp).transpose();
+     248             :     }
+     249         100 :     Pzz += R;
+     250             : 
+     251             :     // compute cross covariance
+     252         100 :     K_t Pxz = K_t::Zero(n, z.rows());
+     253        1000 :     for (int i = 0; i < w; i++)
+     254             :     {
+     255         900 :       Pxz += m_Wc(i) * (S.col(i) - x) * (Z_exp.col(i) - z_exp).transpose();
+     256             :     }
+     257             : 
+     258             :     // compute Kalman gain
+     259         100 :     const z_t inn = (z - z_exp); // innovation
+     260         100 :     const K_t K = computeKalmanGain(sc.x, inn, Pxz, Pzz);
+     261             : 
+     262             :     // check whether the inverse produced valid numbers
+     263         100 :     if (!K.array().isFinite().all())
+     264             :     {
+     265           0 :       ROS_ERROR("UKF: inverting of Pzz in correction update produced non-finite numbers!!! Fix your covariances (the measurement's is probably too low...)");
+     266           0 :       throw inverse_exception();
+     267             :     }
+     268             : 
+     269             :     // correct
+     270         100 :     statecov_t ret;
+     271         100 :     ret.x = x + K * inn;
+     272         100 :     ret.P = P - K * Pzz * K.transpose();
+     273         200 :     return ret;
+     274             :   }
+     275             : 
+     276             :   //}
+     277             : 
+     278             : }  // namespace mrs_lib
+     279             : 
+     280             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/index-sort-f.html b/mrs_lib/include/mrs_lib/index-sort-f.html new file mode 100644 index 0000000000..66dc8e35c5 --- /dev/null +++ b/mrs_lib/include/mrs_lib/index-sort-f.html @@ -0,0 +1,213 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_libHitTotalCoverage
Test:coverage.infoLines:57072478.7 %
Date:2023-11-29 14:09:54Functions:13216381.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
ukf.h +
0.0%
+
0.0 %0 / 40.0 %0 / 2
lkf.h +
63.0%63.0%
+
63.0 %34 / 5440.9 %9 / 22
subscribe_handler.h +
77.5%77.5%
+
77.5 %31 / 4065.0 %13 / 20
transformer.h +
84.2%84.2%
+
84.2 %48 / 5776.5 %13 / 17
attitude_converter.h +
85.2%85.2%
+
85.2 %23 / 2781.8 %9 / 11
timer.h +
100.0%
+
100.0 %4 / 485.7 %6 / 7
param_loader.h +
80.1%80.1%
+
80.1 %213 / 26696.0 %48 / 50
timeout_manager.h +
100.0%
+
100.0 %4 / 4-0 / 0
publisher_handler.h +
100.0%
+
100.0 %3 / 3100.0 %2 / 2
service_client_handler.h +
100.0%
+
100.0 %3 / 3100.0 %3 / 3
gps_conversions.h +
67.6%67.6%
+
67.6 %92 / 136100.0 %4 / 4
utils.h +
100.0%
+
100.0 %15 / 15100.0 %5 / 5
repredictor.h +
90.1%90.1%
+
90.1 %100 / 111100.0 %20 / 20
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/index-sort-l.html b/mrs_lib/include/mrs_lib/index-sort-l.html new file mode 100644 index 0000000000..5ed427038f --- /dev/null +++ b/mrs_lib/include/mrs_lib/index-sort-l.html @@ -0,0 +1,213 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_libHitTotalCoverage
Test:coverage.infoLines:57072478.7 %
Date:2023-11-29 14:09:54Functions:13216381.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
ukf.h +
0.0%
+
0.0 %0 / 40.0 %0 / 2
lkf.h +
63.0%63.0%
+
63.0 %34 / 5440.9 %9 / 22
gps_conversions.h +
67.6%67.6%
+
67.6 %92 / 136100.0 %4 / 4
subscribe_handler.h +
77.5%77.5%
+
77.5 %31 / 4065.0 %13 / 20
param_loader.h +
80.1%80.1%
+
80.1 %213 / 26696.0 %48 / 50
transformer.h +
84.2%84.2%
+
84.2 %48 / 5776.5 %13 / 17
attitude_converter.h +
85.2%85.2%
+
85.2 %23 / 2781.8 %9 / 11
repredictor.h +
90.1%90.1%
+
90.1 %100 / 111100.0 %20 / 20
publisher_handler.h +
100.0%
+
100.0 %3 / 3100.0 %2 / 2
service_client_handler.h +
100.0%
+
100.0 %3 / 3100.0 %3 / 3
timeout_manager.h +
100.0%
+
100.0 %4 / 4-0 / 0
timer.h +
100.0%
+
100.0 %4 / 485.7 %6 / 7
utils.h +
100.0%
+
100.0 %15 / 15100.0 %5 / 5
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/index.html b/mrs_lib/include/mrs_lib/index.html new file mode 100644 index 0000000000..56d140214f --- /dev/null +++ b/mrs_lib/include/mrs_lib/index.html @@ -0,0 +1,213 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_libHitTotalCoverage
Test:coverage.infoLines:57072478.7 %
Date:2023-11-29 14:09:54Functions:13216381.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
attitude_converter.h +
85.2%85.2%
+
85.2 %23 / 2781.8 %9 / 11
gps_conversions.h +
67.6%67.6%
+
67.6 %92 / 136100.0 %4 / 4
lkf.h +
63.0%63.0%
+
63.0 %34 / 5440.9 %9 / 22
param_loader.h +
80.1%80.1%
+
80.1 %213 / 26696.0 %48 / 50
publisher_handler.h +
100.0%
+
100.0 %3 / 3100.0 %2 / 2
repredictor.h +
90.1%90.1%
+
90.1 %100 / 111100.0 %20 / 20
service_client_handler.h +
100.0%
+
100.0 %3 / 3100.0 %3 / 3
subscribe_handler.h +
77.5%77.5%
+
77.5 %31 / 4065.0 %13 / 20
timeout_manager.h +
100.0%
+
100.0 %4 / 4-0 / 0
timer.h +
100.0%
+
100.0 %4 / 485.7 %6 / 7
transformer.h +
84.2%84.2%
+
84.2 %48 / 5776.5 %13 / 17
ukf.h +
0.0%
+
0.0 %0 / 40.0 %0 / 2
utils.h +
100.0%
+
100.0 %15 / 15100.0 %5 / 5
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/lkf.h.func-sort-c.html b/mrs_lib/include/mrs_lib/lkf.h.func-sort-c.html new file mode 100644 index 0000000000..4083fe83d4 --- /dev/null +++ b/mrs_lib/include/mrs_lib/lkf.h.func-sort-c.html @@ -0,0 +1,160 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/lkf.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - lkf.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:345463.0 %
Date:2023-11-29 14:09:54Functions:92240.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib3LKFILi4ELi1ELi2EE13state_predictILi1EEENSt9enable_ifIXneT_Li0EEN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEEE4typeERKNS5_IdLi4ELi4ELi0ELi4ELi4EEERKS6_SD_RKNS5_IdLi1ELi1ELi0ELi1ELi1EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EE18covariance_predictERKN5Eigen6MatrixIdLi4ELi4ELi0ELi4ELi4EEES6_S6_d0
_ZN7mrs_lib3LKFILi4ELi1ELi2EE20correction_optimizedERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEERKNS8_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EE8invert_WEN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EEC2ERKN5Eigen6MatrixIdLi4ELi4ELi0ELi4ELi4EEERKNS3_IdLi4ELi1ELi0ELi4ELi1EEERKNS3_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EEC2Ev0
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE17inverse_exception4whatEv0
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE7predictERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEEd0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE15correction_implILi4EEENSt9enable_ifIXgeT_Li0EENS_12KalmanFilterILi4ELi1ELi2EE10statecov_tEE4typeERKS6_RKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNSC_IdLi2ELi2ELi0ELi2ELi2EEERKNSC_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE17computeKalmanGainERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEERKNS8_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE17inverse_exception4whatEv0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE7correctERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEE0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE7predictERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi4ELi4ELi0ELi4ELi4EEEd0
_ZN7mrs_lib10varstepLKFILi2ELi1ELi1EEC2ERKSt8functionIFN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEEdEERKS2_IFNS4_IdLi2ELi1ELi0ELi2ELi1EEEdEERKNS4_IdLi1ELi2ELi1ELi1ELi2EEE3
_ZN7mrs_lib3LKFILi2ELi1ELi1EEC2Ev3
_ZN7mrs_lib3LKFILi2ELi1ELi1EE8invert_WEN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEE5834
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE15correction_implILi2EEENSt9enable_ifIXgeT_Li0EENS_12KalmanFilterILi2ELi1ELi1EE10statecov_tEE4typeERKS6_RKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESF_RKNSC_IdLi1ELi2ELi1ELi1ELi2EEE5834
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE17computeKalmanGainERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESB_RKNS8_IdLi1ELi2ELi1ELi1ELi2EEE5834
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE7correctERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESB_5834
_ZN7mrs_lib3LKFILi2ELi1ELi1EE13state_predictILi1EEENSt9enable_ifIXneT_Li0EEN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEEE4typeERKNS5_IdLi2ELi2ELi0ELi2ELi2EEERKS6_SD_RKNS5_IdLi1ELi1ELi0ELi1ELi1EEE16542
_ZN7mrs_lib3LKFILi2ELi1ELi1EE18covariance_predictERKN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEES6_S6_d16542
_ZNK7mrs_lib10varstepLKFILi2ELi1ELi1EE7predictERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEEd16542
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/lkf.h.func.html b/mrs_lib/include/mrs_lib/lkf.h.func.html new file mode 100644 index 0000000000..69fd76a652 --- /dev/null +++ b/mrs_lib/include/mrs_lib/lkf.h.func.html @@ -0,0 +1,160 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/lkf.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - lkf.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:345463.0 %
Date:2023-11-29 14:09:54Functions:92240.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib10varstepLKFILi2ELi1ELi1EEC2ERKSt8functionIFN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEEdEERKS2_IFNS4_IdLi2ELi1ELi0ELi2ELi1EEEdEERKNS4_IdLi1ELi2ELi1ELi1ELi2EEE3
_ZN7mrs_lib3LKFILi2ELi1ELi1EE13state_predictILi1EEENSt9enable_ifIXneT_Li0EEN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEEE4typeERKNS5_IdLi2ELi2ELi0ELi2ELi2EEERKS6_SD_RKNS5_IdLi1ELi1ELi0ELi1ELi1EEE16542
_ZN7mrs_lib3LKFILi2ELi1ELi1EE18covariance_predictERKN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEES6_S6_d16542
_ZN7mrs_lib3LKFILi2ELi1ELi1EE8invert_WEN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEE5834
_ZN7mrs_lib3LKFILi2ELi1ELi1EEC2Ev3
_ZN7mrs_lib3LKFILi4ELi1ELi2EE13state_predictILi1EEENSt9enable_ifIXneT_Li0EEN5Eigen6MatrixIdLi4ELi1ELi0ELi4ELi1EEEE4typeERKNS5_IdLi4ELi4ELi0ELi4ELi4EEERKS6_SD_RKNS5_IdLi1ELi1ELi0ELi1ELi1EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EE18covariance_predictERKN5Eigen6MatrixIdLi4ELi4ELi0ELi4ELi4EEES6_S6_d0
_ZN7mrs_lib3LKFILi4ELi1ELi2EE20correction_optimizedERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEERKNS8_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EE8invert_WEN5Eigen6MatrixIdLi2ELi2ELi0ELi2ELi2EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EEC2ERKN5Eigen6MatrixIdLi4ELi4ELi0ELi4ELi4EEERKNS3_IdLi4ELi1ELi0ELi4ELi1EEERKNS3_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZN7mrs_lib3LKFILi4ELi1ELi2EEC2Ev0
_ZNK7mrs_lib10varstepLKFILi2ELi1ELi1EE7predictERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEEd16542
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE15correction_implILi2EEENSt9enable_ifIXgeT_Li0EENS_12KalmanFilterILi2ELi1ELi1EE10statecov_tEE4typeERKS6_RKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESF_RKNSC_IdLi1ELi2ELi1ELi1ELi2EEE5834
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE17computeKalmanGainERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESB_RKNS8_IdLi1ELi2ELi1ELi1ELi2EEE5834
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE17inverse_exception4whatEv0
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE7correctERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESB_5834
_ZNK7mrs_lib3LKFILi2ELi1ELi1EE7predictERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEEd0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE15correction_implILi4EEENSt9enable_ifIXgeT_Li0EENS_12KalmanFilterILi4ELi1ELi2EE10statecov_tEE4typeERKS6_RKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNSC_IdLi2ELi2ELi0ELi2ELi2EEERKNSC_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE17computeKalmanGainERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEERKNS8_IdLi2ELi4ELi0ELi2ELi4EEE0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE17inverse_exception4whatEv0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE7correctERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS8_IdLi2ELi2ELi0ELi2ELi2EEE0
_ZNK7mrs_lib3LKFILi4ELi1ELi2EE7predictERKNS_12KalmanFilterILi4ELi1ELi2EE10statecov_tERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS8_IdLi4ELi4ELi0ELi4ELi4EEEd0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/lkf.h.gcov.html b/mrs_lib/include/mrs_lib/lkf.h.gcov.html new file mode 100644 index 0000000000..d9f50f35e9 --- /dev/null +++ b/mrs_lib/include/mrs_lib/lkf.h.gcov.html @@ -0,0 +1,452 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/lkf.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - lkf.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:345463.0 %
Date:2023-11-29 14:09:54Functions:92240.9 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : /**  \file LKF
+       3             :      \brief Defines LKF - a class, implementing the Linear Kalman Filter \cite LKF, as well as a few specialized variants.
+       4             :      \author Matouš Vrba - vrbamato@fel.cvut.cz
+       5             :  */
+       6             : #ifndef LKFSYSTEMMODELS_H
+       7             : #define LKFSYSTEMMODELS_H
+       8             : 
+       9             : #include <mrs_lib/kalman_filter.h>
+      10             : #include <iostream>
+      11             : 
+      12             : namespace mrs_lib
+      13             : {
+      14             : 
+      15             :   /* class LKF //{ */
+      16             :   /**
+      17             :   * \brief Implementation of the Linear Kalman filter \cite LKF.
+      18             :   *
+      19             :   * The Linear Kalman filter (abbreviated LKF, \cite LKF) may be used for state filtration or estimation of linear
+      20             :   * stochastic discrete systems. It assumes that noise variables are sampled from multivariate gaussian distributions
+      21             :   * and takes into account apriori known parameters of these distributions (namely zero means and covariance matrices,
+      22             :   * which have to be specified by the user and are tunable parameters).
+      23             :   *
+      24             :   * The LKF C++ class itself is templated. This has its advantages and disadvantages. Main disadvantage is that it
+      25             :   * may be harder to use if you're not familiar with C++ templates, which, admittedly, can get somewhat messy,
+      26             :   * espetially during compilation. Another disadvantage is that if used unwisely, the compilation times can get
+      27             :   * much higher when using templates. The main advantage is compile-time checking (if it compiles, then it has
+      28             :   * a lower chance of crashing at runtime) and enabling more effective optimalizations during compilation. Also in case
+      29             :   * of Eigen, the code is arguably more readable when you use aliases to the specific Matrix instances instead of
+      30             :   * having Eigen::MatrixXd and Eigen::VectorXd everywhere.
+      31             :   *
+      32             :   * \tparam n_states         number of states of the system (length of the \f$ \mathbf{x} \f$ vector).
+      33             :   * \tparam n_inputs         number of inputs of the system (length of the \f$ \mathbf{u} \f$ vector).
+      34             :   * \tparam n_measurements   number of measurements of the system (length of the \f$ \mathbf{z} \f$ vector).
+      35             :   *
+      36             :   */
+      37             :   template <int n_states, int n_inputs, int n_measurements>
+      38             :   class LKF : public KalmanFilter<n_states, n_inputs, n_measurements>
+      39             :   {
+      40             :   public:
+      41             :     /* LKF definitions (typedefs, constants etc) //{ */
+      42             :     static constexpr int n = n_states;            /*!< \brief Length of the state vector of the system. */
+      43             :     static constexpr int m = n_inputs;            /*!< \brief Length of the input vector of the system. */
+      44             :     static constexpr int p = n_measurements;      /*!< \brief Length of the measurement vector of the system. */
+      45             :     using Base_class = KalmanFilter<n, m, p>; /*!< \brief Base class of this class. */
+      46             : 
+      47             :     using x_t = typename Base_class::x_t;                /*!< \brief State vector type \f$n \times 1\f$ */
+      48             :     using u_t = typename Base_class::u_t;                /*!< \brief Input vector type \f$m \times 1\f$ */
+      49             :     using z_t = typename Base_class::z_t;                /*!< \brief Measurement vector type \f$p \times 1\f$ */
+      50             :     using P_t = typename Base_class::P_t;                /*!< \brief State uncertainty covariance matrix type \f$n \times n\f$ */
+      51             :     using R_t = typename Base_class::R_t;                /*!< \brief Measurement noise covariance matrix type \f$p \times p\f$ */
+      52             :     using Q_t = typename Base_class::Q_t;                /*!< \brief Process noise covariance matrix type \f$n \times n\f$ */
+      53             :     using statecov_t = typename Base_class::statecov_t;  /*!< \brief Helper struct for passing around the state and its covariance in one variable */
+      54             : 
+      55             :     typedef Eigen::Matrix<double, n, n> A_t;  /*!< \brief System transition matrix type \f$n \times n\f$ */
+      56             :     typedef Eigen::Matrix<double, n, m> B_t;  /*!< \brief Input to state mapping matrix type \f$n \times m\f$ */
+      57             :     typedef Eigen::Matrix<double, p, n> H_t;  /*!< \brief State to measurement mapping matrix type \f$p \times n\f$ */
+      58             :     typedef Eigen::Matrix<double, n, p> K_t;  /*!< \brief Kalman gain matrix type \f$n \times p\f$ */
+      59             : 
+      60             :   /*!
+      61             :     * \brief This exception is thrown when taking the inverse of a matrix fails.
+      62             :     *
+      63             :     * You should catch this exception in your code and act accordingly if it appears
+      64             :     * (e.g. reset the state and covariance or modify the measurement/process noise parameters).
+      65             :     */
+      66             :     struct inverse_exception : public std::exception
+      67             :     {
+      68             :     /*!
+      69             :       * \brief Returns the error message, describing what caused the exception.
+      70             :       *
+      71             :       * \return  The error message, describing what caused the exception.
+      72             :       */
+      73           0 :       const char* what() const throw()
+      74             :       {
+      75           0 :         return "LKF: could not compute matrix inversion!!! Fix your covariances (the measurement's is probably too low...)";
+      76             :       }
+      77             :     };
+      78             :     //}
+      79             : 
+      80             :   public:
+      81             :   /*!
+      82             :     * \brief Convenience default constructor.
+      83             :     *
+      84             :     * This constructor should not be used if applicable. If used, the main constructor has to be called afterwards,
+      85             :     * before using this class, otherwise the LKF object is invalid (not initialized).
+      86             :     */
+      87           3 :     LKF(){};
+      88             : 
+      89             :   /*!
+      90             :     * \brief The main constructor.
+      91             :     *
+      92             :     * \param A             The state transition matrix.
+      93             :     * \param B             The input to state mapping matrix.
+      94             :     * \param H             The state to measurement mapping matrix.
+      95             :     */
+      96           0 :     LKF(const A_t& A, const B_t& B, const H_t& H) : A(A), B(B), H(H){};
+      97             : 
+      98             :     /* correct() method //{ */
+      99             :   /*!
+     100             :     * \brief Applies the correction (update, measurement, data) step of the Kalman filter.
+     101             :     *
+     102             :     * This method applies the linear Kalman filter correction step to the state and covariance
+     103             :     * passed in \p sc using the measurement \p z and measurement noise \p R. The updated state
+     104             :     * and covariance after the correction step is returned.
+     105             :     *
+     106             :     * \param sc          The state and covariance to which the correction step is to be applied.
+     107             :     * \param z           The measurement vector to be used for correction.
+     108             :     * \param R           The measurement noise covariance matrix to be used for correction.
+     109             :     * \return            The state and covariance after the correction update.
+     110             :     */
+     111        5834 :     virtual statecov_t correct(const statecov_t& sc, const z_t& z, const R_t& R) const override
+     112             :     {
+     113             :       /* return correct_optimized(sc, z, R, H); */
+     114        5834 :       return correction_impl(sc, z, R, H);
+     115             :     };
+     116             :     //}
+     117             : 
+     118             :     /* predict() method //{ */
+     119             :   /*!
+     120             :     * \brief Applies the prediction (time) step of the Kalman filter.
+     121             :     *
+     122             :     * This method applies the linear Kalman filter prediction step to the state and covariance
+     123             :     * passed in \p sc using the input \p u and process noise \p Q. The process noise covariance
+     124             :     * \p Q is scaled by the \p dt parameter. The updated state and covariance after
+     125             :     * the prediction step is returned.
+     126             :     *
+     127             :     * \param sc          The state and covariance to which the prediction step is to be applied.
+     128             :     * \param u           The input vector to be used for prediction.
+     129             :     * \param Q           The process noise covariance matrix to be used for prediction.
+     130             :     * \param dt          Used to scale the process noise covariance \p Q.
+     131             :     * \return            The state and covariance after the prediction step.
+     132             :     *
+     133             :     * \note Note that the \p dt parameter is only used to scale the process noise covariance \p Q it
+     134             :     * does not change the system matrices #A or #B (because there is no unambiguous way to do this)!
+     135             :     * If you have a changing time step duration and a dynamic system, you have to change the #A and #B
+     136             :     * matrices manually.
+     137             :     */
+     138           0 :     virtual statecov_t predict(const statecov_t& sc, const u_t& u, const Q_t& Q, [[maybe_unused]] double dt) const override
+     139             :     {
+     140           0 :       statecov_t ret;
+     141           0 :       ret.x = state_predict(A, sc.x, B, u);
+     142           0 :       ret.P = covariance_predict(A, sc.P, Q, dt);
+     143           0 :       return ret;
+     144             :     };
+     145             :     //}
+     146             : 
+     147             :   public:
+     148             :     A_t A;  /*!< \brief The system transition matrix \f$n \times n\f$ */
+     149             :     B_t B;  /*!< \brief The input to state mapping matrix \f$n \times m\f$ */
+     150             :     H_t H;  /*!< \brief The state to measurement mapping matrix \f$p \times n\f$ */
+     151             : 
+     152             :   protected:
+     153             :     /* covariance_predict() method //{ */
+     154       16542 :     static P_t covariance_predict(const A_t& A, const P_t& P, const Q_t& Q, const double dt)
+     155             :     {
+     156       16542 :       return A * P * A.transpose() + dt*Q;
+     157             :     }
+     158             :     //}
+     159             : 
+     160             :     /* state_predict() method //{ */
+     161             :     template <int check = n_inputs>
+     162             :     static inline typename std::enable_if<check == 0, x_t>::type state_predict(const A_t& A, const x_t& x, [[maybe_unused]] const B_t& B,
+     163             :                                                                                [[maybe_unused]] const u_t& u)
+     164             :     {
+     165             :       return A * x;
+     166             :     }
+     167             : 
+     168             :     template <int check = n_inputs>
+     169       16542 :     static inline typename std::enable_if<check != 0, x_t>::type state_predict(const A_t& A, const x_t& x, const B_t& B, const u_t& u)
+     170             :     {
+     171       16542 :       return A * x + B * u;
+     172             :     }
+     173             :     //}
+     174             : 
+     175             :   protected:
+     176             :     /* invert_W() method //{ */
+     177        5834 :     static R_t invert_W(R_t W)
+     178             :     {
+     179        5834 :       Eigen::ColPivHouseholderQR<R_t> qr(W);
+     180        5834 :       if (!qr.isInvertible())
+     181             :       {
+     182             :         // add some stuff to the tmp matrix diagonal to make it invertible
+     183           0 :         R_t ident = R_t::Identity(W.rows(), W.cols());
+     184           0 :         W += 1e-9 * ident;
+     185           0 :         qr.compute(W);
+     186           0 :         if (!qr.isInvertible())
+     187             :         {
+     188             :           // never managed to make this happen except for explicitly putting NaNs in the input
+     189           0 :           throw inverse_exception();
+     190             :         }
+     191             :       }
+     192        5834 :       const R_t W_inv = qr.inverse();
+     193       11668 :       return W_inv;
+     194             :     }
+     195             :     //}
+     196             : 
+     197             :     /* computeKalmanGain() method //{ */
+     198        5834 :     virtual K_t computeKalmanGain(const statecov_t& sc, [[maybe_unused]] const z_t& z, const R_t& R, const H_t& H) const
+     199             :     {
+     200             :       // calculation of the kalman gain K
+     201        5834 :       const R_t W = H * sc.P * H.transpose() + R;
+     202        5834 :       const R_t W_inv = invert_W(W);
+     203        5834 :       const K_t K = sc.P * H.transpose() * W_inv;
+     204       11668 :       return K;
+     205             :     }
+     206             :     //}
+     207             : 
+     208             :     /* correction_impl() method //{ */
+     209             :     template<int check=n>
+     210        5834 :     typename std::enable_if<check >= 0, statecov_t>::type correction_impl(const statecov_t& sc, const z_t& z, const R_t& R, const H_t& H) const
+     211             :     {
+     212             :       // the correction phase
+     213        5834 :       statecov_t ret;
+     214        5834 :       const K_t K = computeKalmanGain(sc, z, R, H);
+     215        5834 :       ret.x = sc.x + K * (z - (H * sc.x));
+     216        5834 :       ret.P = (P_t::Identity() - (K * H)) * sc.P;
+     217       11668 :       return ret;
+     218             :     }
+     219             : 
+     220             :     template<int check=n>
+     221             :     typename std::enable_if<check < 0, statecov_t>::type correction_impl(const statecov_t& sc, const z_t& z, const R_t& R, const H_t& H) const
+     222             :     {
+     223             :       // the correction phase
+     224             :       statecov_t ret;
+     225             :       const K_t K = computeKalmanGain(sc, z, R, H);
+     226             :       ret.x = sc.x + K * (z - (H * sc.x));
+     227             :       ret.P = (P_t::Identity(sc.P.rows(), sc.P.cols()) - (K * H)) * sc.P;
+     228             :       return ret;
+     229             :     }
+     230             :     //}
+     231             : 
+     232             :     // NOT USED METHODS
+     233             :     /* correction_optimized() method //{ */
+     234             :     // No notable performance gain was observed for the matrix sizes we use, so this is not used.
+     235           0 :     static statecov_t correction_optimized(const statecov_t& sc, const z_t& z, const R_t& R, const H_t& H)
+     236             :     {
+     237           0 :       statecov_t ret = sc;
+     238           0 :       const H_t B(H*sc.P.transpose());
+     239           0 :       const K_t K((B*H.transpose() + R).ldlt().solve(B).transpose());
+     240           0 :       ret.x.noalias() += K*(z - H*sc.x);
+     241           0 :       ret.P.noalias() -= K*H*sc.P;
+     242           0 :       return ret;
+     243             :     }
+     244             : 
+     245             :     /* static statecov_t correction_optimized(const statecov_t& sc, const z_t& z, const R_t& R, const H_t& H) */
+     246             :     /* { */
+     247             :     /*   statecov_t ret; */
+     248             :     /*   const H_t B = H*sc.P.transpose(); */
+     249             :     /*   const K_t K = (B*H.transpose() + R).partialPivLu().solve(B).transpose(); */
+     250             :     /*   ret.x = sc.x + K*(z - H*sc.x); */
+     251             :     /*   ret.P = sc.P - K*H*sc.P; */
+     252             :     /*   return ret; */
+     253             :     /* } */
+     254             :     //}
+     255             :   };
+     256             :   //}
+     257             : 
+     258             :   /* class dtMatrixLKF //{ */
+     259             :   template <int n_states, int n_inputs, int n_measurements>
+     260             :   class varstepLKF : public LKF<n_states, n_inputs, n_measurements>
+     261             :   {
+     262             :   public:
+     263             :     /* LKF definitions (typedefs, constants etc) //{ */
+     264             :     static const int n = n_states;
+     265             :     static const int m = n_inputs;
+     266             :     static const int p = n_measurements;
+     267             :     using Base_class = LKF<n, m, p>;
+     268             : 
+     269             :     using x_t = typename Base_class::x_t;
+     270             :     using u_t = typename Base_class::u_t;
+     271             :     using z_t = typename Base_class::z_t;
+     272             :     using P_t = typename Base_class::P_t;
+     273             :     using R_t = typename Base_class::R_t;
+     274             :     using statecov_t = typename Base_class::statecov_t;
+     275             :     using A_t = typename Base_class::A_t;  // measurement mapping p*n
+     276             :     using B_t = typename Base_class::B_t;  // process covariance n*n
+     277             :     using H_t = typename Base_class::H_t;  // measurement mapping p*n
+     278             :     using Q_t = typename Base_class::Q_t;  // process covariance n*n
+     279             : 
+     280             :     using generateA_t = std::function<A_t(double)>;
+     281             :     using generateB_t = std::function<B_t(double)>;
+     282             :     //}
+     283             : 
+     284             :   public:
+     285             : 
+     286             :   /*!
+     287             :     * \brief The main constructor.
+     288             :     *
+     289             :     * \param generateA a function, which returns the state transition matrix \p A based on the time difference \p dt.
+     290             :     * \param generateB a function, which returns the input to state mapping matrix \p B based on the time difference \p dt.
+     291             :     * \param H         the state to measurement mapping matrix.
+     292             :     */
+     293           3 :     varstepLKF(const generateA_t& generateA, const generateB_t& generateB, const H_t& H)
+     294           3 :       : m_generateA(generateA), m_generateB(generateB)
+     295             :     {
+     296           3 :       Base_class::H = H;
+     297           3 :     };
+     298             : 
+     299             :     /* predict() method //{ */
+     300             :   /*!
+     301             :     * \brief Applies the prediction (time) step of the Kalman filter.
+     302             :     *
+     303             :     * This method applies the linear Kalman filter prediction step to the state and covariance
+     304             :     * passed in \p sc using the input \p u and process noise \p Q. The process noise covariance
+     305             :     * \p Q is scaled by the \p dt parameter. The updated state and covariance after
+     306             :     * the prediction step is returned.
+     307             :     *
+     308             :     * \param sc          The state and covariance to which the prediction step is to be applied.
+     309             :     * \param u           The input vector to be used for prediction.
+     310             :     * \param Q           The process noise covariance matrix to be used for prediction.
+     311             :     * \param dt          Used to scale the process noise covariance \p Q and to generate the state transition and input to state mapping matrices \p A and \B using the functions, passed in the object's constructor.
+     312             :     * \return            The state and covariance after the prediction step.
+     313             :     *
+     314             :     * \note Note that the \p dt parameter is used to scale the process noise covariance \p Q and to generate the system matrices #A or #B using the functions, passed in the constructor!
+     315             :     */
+     316       16542 :     virtual statecov_t predict(const statecov_t& sc, const u_t& u, const Q_t& Q, double dt) const override
+     317             :     {
+     318       16542 :       statecov_t ret;
+     319       16542 :       A_t A = m_generateA(dt);
+     320       16542 :       B_t B = m_generateB(dt);
+     321       16542 :       ret.x = Base_class::state_predict(A, sc.x, B, u);
+     322       16542 :       ret.P = Base_class::covariance_predict(A, sc.P, Q, dt);
+     323       33084 :       return ret;
+     324             :     };
+     325             :     //}
+     326             :     
+     327             :   private:
+     328             :     generateA_t m_generateA;
+     329             :     generateB_t m_generateB;
+     330             :   };
+     331             :   //}
+     332             : 
+     333             :   /* class LKF_MRS_odom //{ */
+     334             :   class LKF_MRS_odom : public LKF<3, 1, 1>
+     335             :   {
+     336             :   public:
+     337             :     /* LKF definitions (typedefs, constants etc) //{ */
+     338             :     static const int n = 3;
+     339             :     static const int m = 1;
+     340             :     static const int p = 1;
+     341             :     using Base_class = LKF<n, m, p>;
+     342             : 
+     343             :     using x_t = typename Base_class::x_t;
+     344             :     using u_t = typename Base_class::u_t;
+     345             :     using z_t = typename Base_class::z_t;
+     346             :     using P_t = typename Base_class::P_t;
+     347             :     using R_t = typename Base_class::R_t;
+     348             :     using statecov_t = typename Base_class::statecov_t;
+     349             :     using A_t = typename Base_class::A_t;  // measurement mapping p*n
+     350             :     using B_t = typename Base_class::B_t;  // process covariance n*n
+     351             :     using H_t = typename Base_class::H_t;  // measurement mapping p*n
+     352             :     using Q_t = typename Base_class::Q_t;  // process covariance n*n
+     353             : 
+     354             :     using coeff_A_t = A_t;                            // matrix of constant coefficients in matrix A
+     355             :     typedef Eigen::Matrix<unsigned, n, n> dtexp_A_t;  // matrix of dt exponents in matrix A
+     356             :     using coeff_B_t = B_t;                            // matrix of constant coefficients in matrix B
+     357             :     typedef Eigen::Matrix<unsigned, n, m> dtexp_B_t;  // matrix of dt exponents in matrix B
+     358             :     //}
+     359             : 
+     360             :   public:
+     361             :     LKF_MRS_odom(const std::vector<H_t>& Hs, const double default_dt = 1);
+     362             :     virtual statecov_t predict(const statecov_t& sc, const u_t& u, const Q_t& Q, double dt) const override;
+     363             :     virtual statecov_t correct(const statecov_t& sc, const z_t& z, const R_t& R, int param = 0) const;
+     364             : 
+     365             :   public:
+     366             :     x_t state_predict_optimized(const x_t& x_prev, const u_t& u, double dt) const;
+     367             :     P_t covariance_predict_optimized(const P_t& P, const Q_t& Q, double dt) const;
+     368             : 
+     369             :   private:
+     370             :     std::vector<H_t> m_Hs;
+     371             :   };
+     372             :   //}
+     373             : 
+     374             : }  // namespace mrs_lib
+     375             : 
+     376             : #endif // LKFSYSTEMMODELS_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/param_loader.h.func-sort-c.html b/mrs_lib/include/mrs_lib/param_loader.h.func-sort-c.html new file mode 100644 index 0000000000..c51723ae11 --- /dev/null +++ b/mrs_lib/include/mrs_lib/param_loader.h.func-sort-c.html @@ -0,0 +1,272 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/param_loader.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - param_loader.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:21326680.1 %
Date:2023-11-29 14:09:54Functions:485096.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11ParamLoader10printValueIfEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEE0
_ZN7mrs_lib11ParamLoader13print_warningERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11ParamLoader10printValueERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN6XmlRpc11XmlRpcValueE1
_ZN7mrs_lib11ParamLoader10printValueINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRKS7_RKSt6vectorIT_SaISB_EE1
_ZN7mrs_lib11ParamLoader10printValueIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_1
_ZN7mrs_lib11ParamLoader11addYamlFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11ParamLoader15loadMatrixArrayIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaISE_EE1
_ZN7mrs_lib11ParamLoader15loadMatrixArrayIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaISE_EERKSG_1
_ZN7mrs_lib11ParamLoader16loadMatrixStaticILi3ELi3EfEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN5Eigen6MatrixIT1_XT_EXT0_EXorLNSA_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSD_1EquaaeqT0_Li1EneT_Li1ELSD_0ELSD_0EEXT_EXT0_EEE1
_ZN7mrs_lib11ParamLoader16loadMatrixStaticILi3ELi3EfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLi3ELi3ELi0ELi3ELi3EEEEEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERNS7_IT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSJ_1EquaaeqT0_Li1EneT_Li1ELSJ_0ELSJ_0EEXT_EXT0_EEERKNS2_10MatrixBaseIT2_EE1
_ZN7mrs_lib11ParamLoader16loadMatrixStaticIfEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEEii1
_ZN7mrs_lib11ParamLoader16loadMatrixStaticIfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLin1ELin1ELi0ELin1ELin1EEEEEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERNS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader17loadMatrixDynamicIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEEii1
_ZN7mrs_lib11ParamLoader17loadMatrixDynamicIdN5Eigen14CwiseNullaryOpINS2_8internal18scalar_constant_opIdEENS2_6MatrixIdLin1ELin1ELi0ELin1ELin1EEEEEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERNS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi0ELi0EdEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi3ELi3EfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLi3ELi3ELi0ELi3ELi3EEEEEEENS7_IT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSB_1EquaaeqT0_Li1EneT_Li1ELSB_0ELSB_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT2_EE1
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi3ELi3EfN5Eigen7ProductINS2_14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLi3ELi3ELi0ELi3ELi3EEEEENS4_INS5_18scalar_constant_opIfEES9_EELi0EEEEENS8_IT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSG_1EquaaeqT0_Li1EneT_Li1ELSG_0ELSG_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT2_EE1
_ZN7mrs_lib11ParamLoader17loadParamReusableINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_1
_ZN7mrs_lib11ParamLoader18loadMatrixDynamic2IdN5Eigen13CwiseBinaryOpINS2_8internal17scalar_product_opIddEEKNS2_14CwiseNullaryOpINS4_18scalar_constant_opIdEEKNS2_6MatrixIdLin1ELin1ELi0ELin1ELin1EEEEEKNS7_IS9_SB_EEEEEENSA_IT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader18loadMatrixDynamic2IdN5Eigen14CwiseNullaryOpINS2_8internal18scalar_constant_opIdEENS2_6MatrixIdLin1ELin1ELi0ELin1ELin1EEEEEEENS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader20addYamlFileFromParamERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11ParamLoader25loadMatrixStatic_internalILi0ELi0EdEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS6_NS0_10optional_tENS0_8unique_tE1
_ZN7mrs_lib11ParamLoader4loadIN6XmlRpc11XmlRpcValueEEESt4pairIT_bERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_NS0_10optional_tENS0_8unique_tE1
_ZN7mrs_lib11ParamLoader4loadIdEESt4pairIT_bERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS3_NS0_10optional_tENS0_8unique_tE1
_ZN7mrs_lib11ParamLoader9loadParamIN6XmlRpc11XmlRpcValueEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_RKSC_1
_ZN7mrs_lib11ParamLoader9loadParamINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_1
_ZN7mrs_lib11ParamLoader9loadParamIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZN7mrs_lib11ParamLoader10printValueINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRKS7_RKT_2
_ZN7mrs_lib11ParamLoader16loadMatrixArray2IdEESt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaIS6_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS8_2
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi3ELi3EfEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2IfEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEii2
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2IfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLin1ELin1ELi0ELin1ELin1EEEEEEENS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT0_EEii2
_ZN7mrs_lib11ParamLoader18loadMatrixDynamic2IdEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEii2
_ZN7mrs_lib11ParamLoader4loadINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEESt4pairIT_bERKS7_RKS9_NS0_10optional_tENS0_8unique_tE2
_ZN7mrs_lib11ParamLoader4loadISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEESt4pairIT_bERKS8_RKSC_NS0_10optional_tENS0_8unique_tE2
_ZN7mrs_lib11ParamLoader9loadParamISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEEbRKS8_RT_2
_ZN7mrs_lib11ParamLoaderC2ERKN3ros10NodeHandleEbSt17basic_string_viewIcSt11char_traitsIcEE2
_ZN7mrs_lib11ParamLoader10printValueIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEE3
_ZN7mrs_lib11ParamLoader16loadMatrixArray2IdEESt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaIS6_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE3
_ZN7mrs_lib11ParamLoader20printValue_recursiveERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN6XmlRpc11XmlRpcValueEj3
_ZN7mrs_lib11ParamLoader18loadedSuccessfullyEv4
_ZN7mrs_lib11ParamLoader25loadMatrixStatic_internalILi3ELi3EfEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS6_NS0_10optional_tENS0_8unique_tE4
_ZN7mrs_lib11ParamLoader25loadMatrixStatic_internalIfEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tE4
_ZN7mrs_lib11ParamLoader26loadMatrixDynamic_internalIdEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tE4
_ZN7mrs_lib11ParamLoader24loadMatrixArray_internalIdEESt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaIS6_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS8_NS0_10optional_tENS0_8unique_tE5
_ZN7mrs_lib11ParamLoader11loadMatrixXIdEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tENS0_6swap_tEb6
_ZN7mrs_lib11ParamLoader11loadMatrixXIfEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tENS0_6swap_tEb8
_ZN7mrs_lib11ParamLoader8resolvedERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN7mrs_lib11ParamLoader10printErrorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE17
_ZN7mrs_lib11ParamLoader22check_duplicit_loadingERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE19
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/param_loader.h.func.html b/mrs_lib/include/mrs_lib/param_loader.h.func.html new file mode 100644 index 0000000000..0396bccf8a --- /dev/null +++ b/mrs_lib/include/mrs_lib/param_loader.h.func.html @@ -0,0 +1,272 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/param_loader.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - param_loader.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:21326680.1 %
Date:2023-11-29 14:09:54Functions:485096.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11ParamLoader10printErrorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE17
_ZN7mrs_lib11ParamLoader10printValueERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN6XmlRpc11XmlRpcValueE1
_ZN7mrs_lib11ParamLoader10printValueINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRKS7_RKSt6vectorIT_SaISB_EE1
_ZN7mrs_lib11ParamLoader10printValueINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRKS7_RKT_2
_ZN7mrs_lib11ParamLoader10printValueIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEE3
_ZN7mrs_lib11ParamLoader10printValueIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_1
_ZN7mrs_lib11ParamLoader10printValueIfEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEE0
_ZN7mrs_lib11ParamLoader11addYamlFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11ParamLoader11loadMatrixXIdEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tENS0_6swap_tEb6
_ZN7mrs_lib11ParamLoader11loadMatrixXIfEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tENS0_6swap_tEb8
_ZN7mrs_lib11ParamLoader13print_warningERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11ParamLoader15loadMatrixArrayIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaISE_EE1
_ZN7mrs_lib11ParamLoader15loadMatrixArrayIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaISE_EERKSG_1
_ZN7mrs_lib11ParamLoader16loadMatrixArray2IdEESt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaIS6_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE3
_ZN7mrs_lib11ParamLoader16loadMatrixArray2IdEESt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaIS6_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS8_2
_ZN7mrs_lib11ParamLoader16loadMatrixStaticILi3ELi3EfEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN5Eigen6MatrixIT1_XT_EXT0_EXorLNSA_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSD_1EquaaeqT0_Li1EneT_Li1ELSD_0ELSD_0EEXT_EXT0_EEE1
_ZN7mrs_lib11ParamLoader16loadMatrixStaticILi3ELi3EfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLi3ELi3ELi0ELi3ELi3EEEEEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERNS7_IT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSJ_1EquaaeqT0_Li1EneT_Li1ELSJ_0ELSJ_0EEXT_EXT0_EEERKNS2_10MatrixBaseIT2_EE1
_ZN7mrs_lib11ParamLoader16loadMatrixStaticIfEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEEii1
_ZN7mrs_lib11ParamLoader16loadMatrixStaticIfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLin1ELin1ELi0ELin1ELin1EEEEEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERNS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader17loadMatrixDynamicIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEEii1
_ZN7mrs_lib11ParamLoader17loadMatrixDynamicIdN5Eigen14CwiseNullaryOpINS2_8internal18scalar_constant_opIdEENS2_6MatrixIdLin1ELin1ELi0ELin1ELin1EEEEEEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERNS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi0ELi0EdEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi3ELi3EfEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi3ELi3EfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLi3ELi3ELi0ELi3ELi3EEEEEEENS7_IT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSB_1EquaaeqT0_Li1EneT_Li1ELSB_0ELSB_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT2_EE1
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2ILi3ELi3EfN5Eigen7ProductINS2_14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLi3ELi3ELi0ELi3ELi3EEEEENS4_INS5_18scalar_constant_opIfEES9_EELi0EEEEENS8_IT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELSG_1EquaaeqT0_Li1EneT_Li1ELSG_0ELSG_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT2_EE1
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2IfEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEii2
_ZN7mrs_lib11ParamLoader17loadMatrixStatic2IfN5Eigen14CwiseNullaryOpINS2_8internal18scalar_identity_opIfEENS2_6MatrixIfLin1ELin1ELi0ELin1ELin1EEEEEEENS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT0_EEii2
_ZN7mrs_lib11ParamLoader17loadParamReusableINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_1
_ZN7mrs_lib11ParamLoader18loadMatrixDynamic2IdEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEii2
_ZN7mrs_lib11ParamLoader18loadMatrixDynamic2IdN5Eigen13CwiseBinaryOpINS2_8internal17scalar_product_opIddEEKNS2_14CwiseNullaryOpINS4_18scalar_constant_opIdEEKNS2_6MatrixIdLin1ELin1ELi0ELin1ELin1EEEEEKNS7_IS9_SB_EEEEEENSA_IT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader18loadMatrixDynamic2IdN5Eigen14CwiseNullaryOpINS2_8internal18scalar_constant_opIdEENS2_6MatrixIdLin1ELin1ELi0ELin1ELin1EEEEEEENS7_IT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS2_10MatrixBaseIT0_EEii1
_ZN7mrs_lib11ParamLoader18loadedSuccessfullyEv4
_ZN7mrs_lib11ParamLoader20addYamlFileFromParamERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11ParamLoader20printValue_recursiveERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN6XmlRpc11XmlRpcValueEj3
_ZN7mrs_lib11ParamLoader22check_duplicit_loadingERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE19
_ZN7mrs_lib11ParamLoader24loadMatrixArray_internalIdEESt6vectorIN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEESaIS6_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS8_NS0_10optional_tENS0_8unique_tE5
_ZN7mrs_lib11ParamLoader25loadMatrixStatic_internalILi0ELi0EdEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS6_NS0_10optional_tENS0_8unique_tE1
_ZN7mrs_lib11ParamLoader25loadMatrixStatic_internalILi3ELi3EfEEN5Eigen6MatrixIT1_XT_EXT0_EXorLNS2_14StorageOptionsE0EquaaeqT_Li1EneT0_Li1ELS5_1EquaaeqT0_Li1EneT_Li1ELS5_0ELS5_0EEXT_EXT0_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS6_NS0_10optional_tENS0_8unique_tE4
_ZN7mrs_lib11ParamLoader25loadMatrixStatic_internalIfEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tE4
_ZN7mrs_lib11ParamLoader26loadMatrixDynamic_internalIdEEN5Eigen6MatrixIT_Lin1ELin1ELi0ELin1ELin1EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_iiNS0_10optional_tENS0_8unique_tE4
_ZN7mrs_lib11ParamLoader4loadIN6XmlRpc11XmlRpcValueEEESt4pairIT_bERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS5_NS0_10optional_tENS0_8unique_tE1
_ZN7mrs_lib11ParamLoader4loadINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEESt4pairIT_bERKS7_RKS9_NS0_10optional_tENS0_8unique_tE2
_ZN7mrs_lib11ParamLoader4loadISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEESt4pairIT_bERKS8_RKSC_NS0_10optional_tENS0_8unique_tE2
_ZN7mrs_lib11ParamLoader4loadIdEESt4pairIT_bERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKS3_NS0_10optional_tENS0_8unique_tE1
_ZN7mrs_lib11ParamLoader8resolvedERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE9
_ZN7mrs_lib11ParamLoader9loadParamIN6XmlRpc11XmlRpcValueEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_RKSC_1
_ZN7mrs_lib11ParamLoader9loadParamINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS7_RT_1
_ZN7mrs_lib11ParamLoader9loadParamISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS8_EEEEbRKS8_RT_2
_ZN7mrs_lib11ParamLoader9loadParamIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_1
_ZN7mrs_lib11ParamLoaderC2ERKN3ros10NodeHandleEbSt17basic_string_viewIcSt11char_traitsIcEE2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/param_loader.h.gcov.html b/mrs_lib/include/mrs_lib/param_loader.h.gcov.html new file mode 100644 index 0000000000..6c9e546588 --- /dev/null +++ b/mrs_lib/include/mrs_lib/param_loader.h.gcov.html @@ -0,0 +1,1336 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/param_loader.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - param_loader.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:21326680.1 %
Date:2023-11-29 14:09:54Functions:485096.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : /**  \file
+       3             :      \brief Defines ParamLoader - a convenience class for loading static ROS parameters.
+       4             :      \author Matouš Vrba - vrbamato@fel.cvut.cz
+       5             :  */
+       6             : 
+       7             : #ifndef PARAM_LOADER_H
+       8             : #define PARAM_LOADER_H
+       9             : 
+      10             : #include <ros/ros.h>
+      11             : #include <string>
+      12             : #include <map>
+      13             : #include <unordered_set>
+      14             : #include <iostream>
+      15             : #include <Eigen/Dense>
+      16             : #include <std_msgs/ColorRGBA.h>
+      17             : #include <mrs_lib/param_provider.h>
+      18             : 
+      19             : namespace mrs_lib
+      20             : {
+      21             : 
+      22             : /*** ParamLoader CLASS //{ **/
+      23             : 
+      24             : /**
+      25             : * \brief Convenience class for loading parameters from rosparam server.
+      26             : *
+      27             : * The parameters can be loaded as compulsory. If a compulsory parameter is not found
+      28             : * on the rosparam server (e.g. because it is missing in the launchfile or the yaml config file),
+      29             : * an internal flag is set to false, indicating that the parameter loading procedure failed.
+      30             : * This flag can be checked using the loaded_successfully() method after all parameters were
+      31             : * attempted to be loaded (see usage example usage below).
+      32             : *
+      33             : * The loaded parameter names and corresponding values are printed to stdout by default
+      34             : * for user convenience. Special cases such as loading of Eigen matrices or loading
+      35             : * of std::vectors of various values are also provided.
+      36             : *
+      37             : * To load parameters into the `rosparam` server, use a launchfile prefferably.
+      38             : * See documentation of ROS launchfiles here: http://wiki.ros.org/roslaunch/XML.
+      39             : * Specifically, the `param` XML tag is used for loading parameters directly from the launchfile: http://wiki.ros.org/roslaunch/XML/param,
+      40             : * and the `rosparam` XML tag tag is used for loading parameters from a `yaml` file: http://wiki.ros.org/roslaunch/XML/rosparam.
+      41             : *
+      42             : */
+      43             : class ParamLoader
+      44             : {
+      45             : 
+      46             : private:
+      47             :   enum unique_t
+      48             :   {
+      49             :     UNIQUE = true,
+      50             :     REUSABLE = false
+      51             :   };
+      52             :   enum optional_t
+      53             :   {
+      54             :     OPTIONAL = true,
+      55             :     COMPULSORY = false
+      56             :   };
+      57             :   enum swap_t
+      58             :   {
+      59             :     SWAP = true,
+      60             :     NO_SWAP = false
+      61             :   };
+      62             : 
+      63             :   template <typename T>
+      64             :   using MatrixX = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;
+      65             : 
+      66             : private:
+      67             :   bool m_load_successful, m_print_values;
+      68             :   std::string m_node_name;
+      69             :   std::string m_prefix;
+      70             :   const ros::NodeHandle& m_nh;
+      71             :   mrs_lib::ParamProvider m_pp;
+      72             :   std::unordered_set<std::string> m_loaded_params;
+      73             : 
+      74             :   /* printing helper functions //{ */
+      75             :   /* printError and print_warning functions //{*/
+      76          17 :   void printError(const std::string& str)
+      77             :   {
+      78          17 :     if (m_node_name.empty())
+      79          17 :       ROS_ERROR_STREAM(str);
+      80             :     else
+      81           0 :       ROS_ERROR_STREAM("[" << m_node_name << "]: " << str);
+      82          17 :   }
+      83           0 :   void print_warning(const std::string& str)
+      84             :   {
+      85           0 :     if (m_node_name.empty())
+      86           0 :       ROS_WARN_STREAM(str);
+      87             :     else
+      88           0 :       ROS_WARN_STREAM("[" << m_node_name << "]: " << str);
+      89           0 :   }
+      90             :   //}
+      91             : 
+      92             :   /* printValue function and overloads //{ */
+      93             : 
+      94             :   template <typename T>
+      95           3 :   void printValue(const std::string& name, const T& value)
+      96             :   {
+      97           3 :     if (m_node_name.empty())
+      98           3 :       std::cout << "\t" << name << ":\t" << value << std::endl;
+      99             :     else
+     100           0 :       ROS_INFO_STREAM("[" << m_node_name << "]: parameter '" << name << "':\t" << value);
+     101           3 :   }
+     102             : 
+     103             :   template <typename T>
+     104           1 :   void printValue(const std::string& name, const std::vector<T>& value)
+     105             :   {
+     106           2 :     std::stringstream strstr;
+     107           1 :     if (m_node_name.empty())
+     108           1 :       strstr << "\t";
+     109           1 :     strstr << name << ":\t";
+     110           1 :     size_t it = 0;
+     111           5 :     for (const auto& elem : value)
+     112             :     {
+     113           4 :       strstr << elem;
+     114           4 :       if (it < value.size() - 1)
+     115           3 :         strstr << ", ";
+     116           4 :       it++;
+     117             :     }
+     118           1 :     if (m_node_name.empty())
+     119           1 :       std::cout << strstr.str() << std::endl;
+     120             :     else
+     121           0 :       ROS_INFO_STREAM("[" << m_node_name << "]: parameter '" << strstr.str());
+     122           1 :   }
+     123             : 
+     124             :   template <typename T1, typename T2>
+     125             :   void printValue(const std::string& name, const std::map<T1, T2>& value)
+     126             :   {
+     127             :     std::stringstream strstr;
+     128             :     if (m_node_name.empty())
+     129             :       strstr << "\t";
+     130             :     strstr << name << ":" << std::endl;
+     131             :     size_t it = 0;
+     132             :     for (const auto& pair : value)
+     133             :     {
+     134             :       strstr << pair.first << " = " << pair.second;
+     135             :       if (it < value.size() - 1)
+     136             :         strstr << std::endl;
+     137             :       it++;
+     138             :     }
+     139             :     if (m_node_name.empty())
+     140             :       std::cout << strstr.str() << std::endl;
+     141             :     else
+     142             :       ROS_INFO_STREAM("[" << m_node_name << "]: parameter '" << strstr.str());
+     143             :   }
+     144             : 
+     145             :   template <typename T>
+     146           3 :   void printValue(const std::string& name, const MatrixX<T>& value)
+     147             :   {
+     148           6 :     std::stringstream strstr;
+     149             :     /* const Eigen::IOFormat fmt(4, 0, ", ", "\n", "\t\t[", "]"); */
+     150             :     /* strstr << value.format(fmt); */
+     151           9 :     const Eigen::IOFormat fmt;
+     152           3 :     strstr << value.format(fmt);
+     153           3 :     if (m_node_name.empty())
+     154           3 :       std::cout << "\t" << name << ":\t" << std::endl << strstr.str() << std::endl;
+     155             :     else
+     156           0 :       ROS_INFO_STREAM("[" << m_node_name << "]: parameter '" << name << "':" << std::endl << strstr.str());
+     157           3 :   }
+     158             : 
+     159           3 :   std::string printValue_recursive(const std::string& name, XmlRpc::XmlRpcValue& value, unsigned depth = 0)
+     160             :   {
+     161           6 :     std::stringstream strstr;
+     162           6 :     for (unsigned it = 0; it < depth; it++)
+     163           3 :       strstr << "\t";
+     164           3 :     strstr << name << ":";
+     165           3 :     switch (value.getType())
+     166             :     {
+     167           1 :       case XmlRpc::XmlRpcValue::TypeArray:
+     168             :         {
+     169           2 :           for (int it = 0; it < value.size(); it++)
+     170             :           {
+     171           1 :             strstr << std::endl;
+     172           2 :             const std::string name = "[" + std::to_string(it) + "]";
+     173           1 :             strstr << printValue_recursive(name, value[it], depth+1);
+     174             :           }
+     175           1 :           break;
+     176             :         }
+     177           1 :       case XmlRpc::XmlRpcValue::TypeStruct:
+     178             :         {
+     179           1 :           int it = 0;
+     180           2 :           for (auto& pair : value)
+     181             :           {
+     182           1 :             strstr << std::endl;
+     183           1 :             strstr << printValue_recursive(pair.first, pair.second, depth+1);
+     184           1 :             it++;
+     185             :           }
+     186           1 :           break;
+     187             :         }
+     188           1 :       default:
+     189             :         {
+     190           1 :           strstr << "\t" << value;
+     191           1 :           break;
+     192             :         }
+     193             :     }
+     194           6 :     return strstr.str();
+     195             :   }
+     196             : 
+     197           1 :   void printValue(const std::string& name, XmlRpc::XmlRpcValue& value)
+     198             :   {
+     199           2 :     const std::string txt = printValue_recursive(name, value);
+     200           1 :     if (m_node_name.empty())
+     201           1 :       std::cout << txt << std::endl;
+     202             :     else
+     203           0 :       ROS_INFO_STREAM("[" << m_node_name << "]: parameter '" << txt);
+     204           1 :   }
+     205             : 
+     206             :   //}
+     207             :   
+     208           9 :   std::string resolved(const std::string& param_name)
+     209             :   {
+     210           9 :     return m_nh.resolveName(param_name);
+     211             :   }
+     212             :   //}
+     213             : 
+     214             :   /* check_duplicit_loading checks whether the parameter was already loaded - returns true if yes //{ */
+     215          19 :   bool check_duplicit_loading(const std::string& name)
+     216             :   {
+     217          19 :     if (m_loaded_params.count(name))
+     218             :     {
+     219          12 :       printError(std::string("Tried to load parameter ") + name + std::string(" twice"));
+     220          12 :       m_load_successful = false;
+     221          12 :       return true;
+     222             :     } else
+     223             :     {
+     224           7 :       return false;
+     225             :     }
+     226             :   }
+     227             :   //}
+     228             : 
+     229             :   /* loadMatrixStatic_internal helper function for loading static Eigen matrices //{ */
+     230             :   template <int rows, int cols, typename T>
+     231           5 :   Eigen::Matrix<T, rows, cols> loadMatrixStatic_internal(const std::string& name, const Eigen::Matrix<T, rows, cols>& default_value, optional_t optional, unique_t unique)
+     232             :   {
+     233          10 :     MatrixX<T> dynamic = loadMatrixX(name, MatrixX<T>(default_value), rows, cols, optional, unique, NO_SWAP);
+     234           5 :     if (dynamic.rows() == rows || dynamic.cols() == cols)
+     235           5 :       return dynamic;
+     236             :     else
+     237           0 :       return default_value;
+     238             :   }
+     239             :   //}
+     240             : 
+     241             :   /* helper functions for loading dynamic Eigen matrices //{ */
+     242             :   // loadMatrixX helper function for loading dynamic Eigen matrices //{
+     243             :   template <typename T>
+     244          14 :   MatrixX<T> loadMatrixX(const std::string& name, const MatrixX<T>& default_value, int rows, int cols = Eigen::Dynamic, optional_t optional = OPTIONAL, unique_t unique = UNIQUE, swap_t swap = NO_SWAP, bool printValues = true)
+     245             :   {
+     246          28 :     const std::string name_prefixed = m_prefix + name;
+     247          14 :     MatrixX<T> loaded = default_value;
+     248             :     // first, check if the user already tried to load this parameter
+     249          14 :     if (unique && check_duplicit_loading(name_prefixed))
+     250          12 :       return loaded;
+     251             : 
+     252             :     // this function only accepts dynamic columns (you can always transpose the matrix afterward)
+     253           2 :     if (rows < 0)
+     254             :     {
+     255             :       // if the parameter was compulsory, alert the user and set the flag
+     256           0 :       printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved(name_prefixed));
+     257           0 :       m_load_successful = false;
+     258           0 :       return loaded;
+     259             :     }
+     260           2 :     bool expect_zero_matrix = rows == 0;
+     261           2 :     if (expect_zero_matrix)
+     262             :     {
+     263           1 :       if (cols > 0)
+     264             :       {
+     265           0 :         printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved(name_prefixed) + ". One dimension indicates zero matrix, but other expects non-zero.");
+     266           0 :         m_load_successful = false;
+     267           0 :         return loaded;
+     268             :       }
+     269             :     }
+     270             : 
+     271             : 
+     272           2 :     bool cur_load_successful = true;
+     273           2 :     bool check_size_exact = true;
+     274           2 :     if (cols <= 0)  // this means that the cols dimension is dynamic or a zero matrix is expected
+     275           1 :       check_size_exact = false;
+     276             : 
+     277           4 :     std::vector<T> tmp_vec;
+     278             :     // try to load the parameter
+     279           2 :     bool success = m_pp.getParam(name_prefixed, tmp_vec);
+     280             :     // check if the loaded vector has correct length
+     281           2 :     bool correct_size = (int)tmp_vec.size() == rows * cols;
+     282           2 :     if (!check_size_exact && !expect_zero_matrix)
+     283           0 :       correct_size = (int)tmp_vec.size() % rows == 0;  // if the cols dimension is dynamic, the size just has to be divisable by rows
+     284             : 
+     285           2 :     if (success && correct_size)
+     286             :     {
+     287             :       // if successfully loaded, everything is in order
+     288             :       // transform the vector to the matrix
+     289           2 :       if (cols <= 0 && rows > 0)
+     290           0 :         cols = tmp_vec.size() / rows;
+     291           2 :       if (swap)
+     292             :       {
+     293           0 :         int tmp = cols;
+     294           0 :         cols = rows;
+     295           0 :         rows = tmp;
+     296             :       }
+     297           2 :       loaded = Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>, Eigen::Unaligned>(tmp_vec.data(), rows, cols);
+     298             :     } else
+     299             :     {
+     300           0 :       if (success && !correct_size)
+     301             :       {
+     302             :         // warn the user that this parameter was not successfully loaded because of wrong vector length (might be an oversight)
+     303           0 :         std::string warning =
+     304             :             std::string("Matrix parameter ") + name_prefixed
+     305             :             + std::string(" could not be loaded because the vector has a wrong length " + std::to_string(tmp_vec.size()) + " instead of expected ");
+     306             :         // process the message correctly based on whether the loaded matrix should be dynamic or static
+     307           0 :         if (cols <= 0)  // for dynamic matrices
+     308           0 :           warning = warning + std::string("number divisible by ") + std::to_string(rows);
+     309             :         else  // for static matrices
+     310           0 :           warning = warning + std::to_string(rows * cols);
+     311           0 :         print_warning(warning);
+     312             :       }
+     313             :       // if it was not loaded, set the default value
+     314           0 :       loaded = default_value;
+     315           0 :       if (!optional)
+     316             :       {
+     317             :         // if the parameter was compulsory, alert the user and set the flag
+     318           0 :         printError(std::string("Could not load non-optional parameter ") + resolved(name_prefixed));
+     319           0 :         cur_load_successful = false;
+     320             :       }
+     321             :     }
+     322             : 
+     323             :     // check if load was a success
+     324           2 :     if (cur_load_successful)
+     325             :     {
+     326           2 :       if (m_print_values && printValues)
+     327           1 :         printValue(name_prefixed, loaded);
+     328           2 :       m_loaded_params.insert(name_prefixed);
+     329             :     } else
+     330             :     {
+     331           0 :       m_load_successful = false;
+     332             :     }
+     333             :     // finally, return the resulting value
+     334           2 :     return loaded;
+     335             :   }
+     336             :   //}
+     337             : 
+     338             :   /* loadMatrixArray_internal helper function for loading an array of EigenXd matrices with known dimensions //{ */
+     339             :   template <typename T>
+     340           5 :   std::vector<MatrixX<T>> loadMatrixArray_internal(const std::string& name, const std::vector<MatrixX<T>>& default_value, optional_t optional, unique_t unique)
+     341             :   {
+     342          10 :     const std::string name_prefixed = m_prefix + name;
+     343             :     int rows;
+     344          10 :     std::vector<int> cols;
+     345           5 :     bool success = true;
+     346           5 :     success = success && m_pp.getParam(name_prefixed + "/rows", rows);
+     347           5 :     success = success && m_pp.getParam(name_prefixed + "/cols", cols);
+     348             : 
+     349          10 :     std::vector<MatrixX<T>> loaded;
+     350           5 :     loaded.reserve(cols.size());
+     351             : 
+     352           5 :     int total_cols = 0;
+     353             :     /* check correctness of loaded parameters so far calculate the total dimension //{ */
+     354             : 
+     355           5 :     if (!success)
+     356             :     {
+     357           4 :       printError(std::string("Failed to load ") + resolved(name_prefixed) + std::string("/rows or ") + resolved(name_prefixed) + std::string("/cols"));
+     358           4 :       m_load_successful = false;
+     359           4 :       return default_value;
+     360             :     }
+     361           1 :     if (rows < 0)
+     362             :     {
+     363           0 :       printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved(name_prefixed) + std::string(" (rows and cols must be >= 0)"));
+     364           0 :       m_load_successful = false;
+     365           0 :       return default_value;
+     366             :     }
+     367           3 :     for (const auto& col : cols)
+     368             :     {
+     369           2 :       if (col < 0)
+     370             :       {
+     371           0 :         printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved(name_prefixed) + std::string(" (rows and cols must be >= 0)"));
+     372           0 :         m_load_successful = false;
+     373           0 :         return default_value;
+     374             :       }
+     375           2 :       total_cols += col;
+     376             :     }
+     377             :     
+     378             :     //}
+     379             : 
+     380           3 :     const MatrixX<T> loaded_matrix = loadMatrixX(name + "/data", MatrixX<T>(), rows, total_cols, optional, unique, NO_SWAP, false);
+     381             :     /* std::cout << "loaded_matrix: " << loaded_matrix << std::endl; */
+     382             :     /* std::cout << "loaded_matrix: " << loaded_matrix.rows() << "x" << loaded_matrix.cols() << std::endl; */
+     383             :     /* std::cout << "expected dims: " << rows << "x" << total_cols << std::endl; */
+     384           1 :     if (loaded_matrix.rows() != rows || loaded_matrix.cols() != total_cols)
+     385             :     {
+     386           0 :       m_load_successful = false;
+     387           0 :       return default_value;
+     388             :     }
+     389             : 
+     390           1 :     int cols_loaded = 0;
+     391           3 :     for (unsigned it = 0; it < cols.size(); it++)
+     392             :     {
+     393           2 :       const int cur_cols = cols.at(it);
+     394           2 :       const MatrixX<T> cur_mat = loaded_matrix.block(0, cols_loaded, rows, cur_cols);
+     395             :       /* std::cout << "cur_mat: " << cur_mat << std::endl; */
+     396           2 :       loaded.push_back(cur_mat);
+     397           2 :       cols_loaded += cur_cols;
+     398           2 :       printValue(name_prefixed + "/matrix#" + std::to_string(it), cur_mat);
+     399             :     }
+     400           1 :     return loaded;
+     401             :   }
+     402             :   //}
+     403             : 
+     404             :   /* loadMatrixStatic_internal helper function for loading EigenXd matrices with known dimensions //{ */
+     405             :   template <typename T>
+     406           4 :   MatrixX<T> loadMatrixStatic_internal(const std::string& name, const MatrixX<T>& default_value, int rows, int cols, optional_t optional, unique_t unique)
+     407             :   {
+     408           8 :     MatrixX<T> loaded = default_value;
+     409             :     // first, check that at least one dimension is set
+     410           4 :     if (rows <= 0 || cols <= 0)
+     411             :     {
+     412           0 :       printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved(name) + std::string(" (use loadMatrixDynamic?)"));
+     413           0 :       m_load_successful = false;
+     414           0 :       return loaded;
+     415             :     }
+     416             : 
+     417           4 :     return loadMatrixX(name, default_value, rows, cols, optional, unique, NO_SWAP);
+     418             :   }
+     419             :   //}
+     420             : 
+     421             :   /* loadMatrixDynamic_internal helper function for loading Eigen matrices with one dynamic (unspecified) dimension //{ */
+     422             :   template <typename T>
+     423           4 :   MatrixX<T> loadMatrixDynamic_internal(const std::string& name, const MatrixX<T>& default_value, int rows, int cols, optional_t optional, unique_t unique)
+     424             :   {
+     425           8 :     MatrixX<T> loaded = default_value;
+     426             : 
+     427             :     // next, check that at least one dimension is set
+     428           4 :     if (rows <= 0 && cols <= 0)
+     429             :     {
+     430           0 :       printError(std::string("Invalid expected matrix dimensions for parameter ") + resolved(name) + std::string(" (at least one dimension must be specified)"));
+     431           0 :       m_load_successful = false;
+     432           0 :       return loaded;
+     433             :     }
+     434             : 
+     435           4 :     swap_t swap = NO_SWAP;
+     436           4 :     if (rows <= 0)
+     437             :     {
+     438           0 :       int tmp = rows;
+     439           0 :       rows = cols;
+     440           0 :       cols = tmp;
+     441           0 :       swap = SWAP;
+     442             :     }
+     443           4 :     return loadMatrixX(name, default_value, rows, cols, optional, unique, swap);
+     444             :   }
+     445             :   //}
+     446             :   //}
+     447             : 
+     448             :   /* load helper function for generic types //{ */
+     449             :   // This function tries to load a parameter with name 'name' and a default value.
+     450             :   // You can use the flag 'optional' to not throw a ROS_ERROR when the parameter
+     451             :   // cannot be loaded and the flag 'printValues' to set whether the loaded
+     452             :   // value and name of the parameter should be printed to cout.
+     453             :   // If 'optional' is set to false and the parameter could not be loaded,
+     454             :   // the flag 'load_successful' is set to false and a ROS_ERROR message
+     455             :   // is printer.
+     456             :   // If 'unique' flag is set to false then the parameter is not checked
+     457             :   // for being loaded twice.
+     458             :   // Returns a tuple, containing either the loaded or the default value and a bool,
+     459             :   // indicating if the value was loaded (true) or the default value was used (false).
+     460             :   template <typename T>
+     461           6 :   std::pair<T, bool> load(const std::string& name, const T& default_value, optional_t optional = OPTIONAL, unique_t unique = UNIQUE)
+     462             :   {
+     463          12 :     const std::string name_prefixed = m_prefix + name;
+     464          11 :     T loaded = default_value;
+     465           6 :     if (unique && check_duplicit_loading(name_prefixed))
+     466           0 :       return {loaded, false};
+     467             : 
+     468           6 :     bool cur_load_successful = true;
+     469             :     // try to load the parameter
+     470           6 :     const bool success = m_pp.getParam(name_prefixed, loaded);
+     471           6 :     if (!success)
+     472             :     {
+     473             :       // if it was not loaded, set the default value
+     474           1 :       loaded = default_value;
+     475           1 :       if (!optional)
+     476             :       {
+     477             :         // if the parameter was compulsory, alert the user and set the flag
+     478           1 :         printError(std::string("Could not load non-optional parameter ") + resolved(name_prefixed));
+     479           1 :         cur_load_successful = false;
+     480             :       }
+     481             :     }
+     482             : 
+     483           6 :     if (cur_load_successful)
+     484             :     {
+     485             :       // everything is fine and just print the name_prefixed and value if required
+     486           5 :       if (m_print_values)
+     487           5 :         printValue(name_prefixed, loaded);
+     488             :       // mark the param name_prefixed as successfully loaded
+     489           5 :       m_loaded_params.insert(name_prefixed);
+     490             :     } else
+     491             :     {
+     492           1 :       m_load_successful = false;
+     493             :     }
+     494             :     // finally, return the resulting value
+     495           6 :     return {loaded, success};
+     496             :   }
+     497             :   //}
+     498             : 
+     499             : public:
+     500             :   /*!
+     501             :     * \brief Main constructor.
+     502             :     *
+     503             :     * \param nh            The parameters will be loaded from rosparam using this node handle.
+     504             :     * \param printValues  If true, the loaded values will be printed to stdout using std::cout or ROS_INFO if node_name is not empty.
+     505             :     * \param node_name     Optional node name used when printing the loaded values or loading errors.
+     506             :     */
+     507           2 :   ParamLoader(const ros::NodeHandle& nh, bool printValues = true, std::string_view node_name = std::string())
+     508           2 :       : m_load_successful(true),
+     509             :         m_print_values(printValues),
+     510             :         m_node_name(node_name),
+     511             :         m_nh(nh),
+     512           2 :         m_pp(nh, m_node_name)
+     513             :   {
+     514             :     /* std::cout << "Initialized1 ParamLoader for node " << node_name << std::endl; */
+     515           2 :   }
+     516             : 
+     517             :   /* Constructor overloads //{ */
+     518             :   /*!
+     519             :     * \brief Convenience overload to enable writing ParamLoader pl(nh, node_name);
+     520             :     *
+     521             :     * \param nh            The parameters will be loaded from rosparam using this node handle.
+     522             :     * \param node_name     Optional node name used when printing the loaded values or loading errors.
+     523             :     */
+     524             :   ParamLoader(const ros::NodeHandle& nh, std::string_view node_name)
+     525             :       : ParamLoader(nh, true, node_name)
+     526             :   {
+     527             :     /* std::cout << "Initialized2 ParamLoader for node " << node_name << std::endl; */
+     528             :   }
+     529             : 
+     530             :   /*!
+     531             :     * \brief Convenience overload to enable writing ParamLoader pl(nh, "node_name");
+     532             :     *
+     533             :     * \param nh            The parameters will be loaded from rosparam using this node handle.
+     534             :     * \param node_name     Optional node name used when printing the loaded values or loading errors.
+     535             :     */
+     536             :   ParamLoader(const std::string& filepath, const ros::NodeHandle& nh)
+     537             :     : ParamLoader(nh, "none")
+     538             :   {
+     539             :     YAML::Node node = YAML::Load(filepath);
+     540             :   }
+     541             :   //}
+     542             : 
+     543             :   /* setPrefix function //{ */
+     544             :   
+     545             :   /*!
+     546             :     * \brief All loaded parameters will be prefixed with this string.
+     547             :     *
+     548             :     * \param prefix  the prefix to be applied to all loaded parameters from now on.
+     549             :     */
+     550             :   void setPrefix(const std::string& prefix)
+     551             :   {
+     552             :     m_prefix = prefix;
+     553             :   }
+     554             :   
+     555             :   //}
+     556             : 
+     557             :   /* getPrefix function //{ */
+     558             :   
+     559             :   /*!
+     560             :     * \brief Returns the current parameter name prefix.
+     561             :     *
+     562             :     * \return the current prefix to be applied to the loaded parameters.
+     563             :     */
+     564             :   std::string getPrefix()
+     565             :   {
+     566             :     return m_prefix;
+     567             :   }
+     568             :   
+     569             :   //}
+     570             : 
+     571             :   /* addYamlFile() function //{ */
+     572             :   
+     573             :   /*!
+     574             :     * \brief Adds the specified file as a source of static parameters.
+     575             :     *
+     576             :     * \param filepath The full path to the yaml file to be loaded.
+     577             :     * \return true if loading and parsing the file was successful, false otherwise.
+     578             :     */
+     579           1 :   bool addYamlFile(const std::string& filepath)
+     580             :   {
+     581           1 :     return m_pp.addYamlFile(filepath);
+     582             :   }
+     583             :   //}
+     584             : 
+     585             :   /* addYamlFileFromParam() function //{ */
+     586             :   
+     587             :   /*!
+     588             :     * \brief Adds the specified file as a source of static parameters.
+     589             :     *
+     590             :     * \param filepath The full path to the yaml file to be loaded.
+     591             :     * \return true if loading and parsing the file was successful, false otherwise.
+     592             :     */
+     593           1 :   bool addYamlFileFromParam(const std::string& param_name)
+     594             :   {
+     595           2 :     std::string filepath;
+     596           1 :     if (!loadParam(param_name, filepath))
+     597           0 :       return false;
+     598           1 :     return m_pp.addYamlFile(filepath);
+     599             :   }
+     600             :   //}
+     601             : 
+     602             :   /* loadedSuccessfully function //{ */
+     603             :   /*!
+     604             :     * \brief Indicates whether all compulsory parameters were successfully loaded.
+     605             :     *
+     606             :     * \return false if any compulsory parameter was not loaded (is not present at rosparam server). Otherwise returns true.
+     607             :     */
+     608           4 :   bool loadedSuccessfully()
+     609             :   {
+     610           4 :     return m_load_successful;
+     611             :   }
+     612             :   //}
+     613             : 
+     614             :   /* loadParam function for optional parameters //{ */
+     615             :   /*!
+     616             :     * \brief Loads a parameter from the rosparam server with a default value.
+     617             :     *
+     618             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     619             :     * the default value is used.
+     620             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     621             :     *
+     622             :     * \param name          Name of the parameter in the rosparam server.
+     623             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     624             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     625             :     * \return              true if the parameter was loaded from \p rosparam, false if the default value was used.
+     626             :     */
+     627             :   template <typename T>
+     628           1 :   bool loadParam(const std::string& name, T& out_value, const T& default_value)
+     629             :   {
+     630           1 :     const auto [ret, success] = load<T>(name, default_value, OPTIONAL, UNIQUE);
+     631           1 :     out_value = ret;
+     632           2 :     return success;
+     633             :   }
+     634             :   /*!
+     635             :     * \brief Loads a parameter from the rosparam server with a default value.
+     636             :     *
+     637             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     638             :     * the default value is used.
+     639             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     640             :     *
+     641             :     * \param name          Name of the parameter in the rosparam server.
+     642             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     643             :     * \return              The loaded parameter value.
+     644             :     */
+     645             :   template <typename T>
+     646             :   T loadParam2(const std::string& name, const T& default_value)
+     647             :   {
+     648             :     const auto loaded = load<T>(name, default_value, OPTIONAL, UNIQUE);
+     649             :     return loaded.first;
+     650             :   }
+     651             :   /*!
+     652             :     * \brief Loads a parameter from the rosparam server with a default value.
+     653             :     *
+     654             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     655             :     * the default value is used.
+     656             :     * Using this method, the parameter can be loaded multiple times using the same ParamLoader instance without error.
+     657             :     *
+     658             :     * \param name          Name of the parameter in the rosparam server.
+     659             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     660             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     661             :     * \return              true if the parameter was loaded from \p rosparam, false if the default value was used.
+     662             :     */
+     663             :   template <typename T>
+     664             :   bool loadParamReusable(const std::string& name, T& out_value, const T& default_value)
+     665             :   {
+     666             :     const auto [ret, success] = load<T>(name, default_value, OPTIONAL, REUSABLE);
+     667             :     out_value = ret;
+     668             :     return success;
+     669             :   }
+     670             :   /*!
+     671             :     * \brief Loads an optional reusable parameter from the rosparam server.
+     672             :     *
+     673             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     674             :     * the default value is used.
+     675             :     * Using this method, the parameter can be loaded multiple times using the same ParamLoader instance without error.
+     676             :     *
+     677             :     * \param name          Name of the parameter in the rosparam server.
+     678             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     679             :     * \return              The loaded parameter value.
+     680             :     */
+     681             :   template <typename T>
+     682             :   T loadParamReusable2(const std::string& name, const T& default_value)
+     683             :   {
+     684             :     const auto [ret, success] = load<T>(name, default_value, OPTIONAL, REUSABLE);
+     685             :     return ret;
+     686             :   }
+     687             :   //}
+     688             : 
+     689             :   /* loadParam function for compulsory parameters //{ */
+     690             :   /*!
+     691             :     * \brief Loads a compulsory parameter from the rosparam server.
+     692             :     *
+     693             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     694             :     * the loading process is unsuccessful (loaded_successfully() will return false).
+     695             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     696             :     *
+     697             :     * \param name          Name of the parameter in the rosparam server.
+     698             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     699             :     * \return              true if the parameter was loaded from \p rosparam, false if the default value was used.
+     700             :     */
+     701             :   template <typename T>
+     702           4 :   bool loadParam(const std::string& name, T& out_value)
+     703             :   {
+     704           7 :     const auto [ret, success] = load<T>(name, T(), COMPULSORY, UNIQUE);
+     705           4 :     out_value = ret;
+     706           7 :     return success;
+     707             :   }
+     708             :   /*!
+     709             :     * \brief Loads a compulsory parameter from the rosparam server.
+     710             :     *
+     711             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     712             :     * the loading process is unsuccessful (loaded_successfully() will return false).
+     713             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     714             :     *
+     715             :     * \param name          Name of the parameter in the rosparam server.
+     716             :     * \return              The loaded parameter value.
+     717             :     */
+     718             :   template <typename T>
+     719             :   T loadParam2(const std::string& name)
+     720             :   {
+     721             :     const auto [ret, success] = load<T>(name, T(), COMPULSORY, UNIQUE);
+     722             :     return ret;
+     723             :   }
+     724             :   /*!
+     725             :     * \brief Loads a compulsory parameter from the rosparam server.
+     726             :     *
+     727             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     728             :     * the loading process is unsuccessful (loaded_successfully() will return false).
+     729             :     * Using this method, the parameter can be loaded multiple times using the same ParamLoader instance without error.
+     730             :     *
+     731             :     * \param name          Name of the parameter in the rosparam server.
+     732             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     733             :     * \return              true if the parameter was loaded from \p rosparam, false if the default value was used.
+     734             :     */
+     735             :   template <typename T>
+     736           1 :   bool loadParamReusable(const std::string& name, T& out_value)
+     737             :   {
+     738           2 :     const auto [ret, success] = load<T>(name, T(), COMPULSORY, REUSABLE);
+     739           1 :     out_value = ret;
+     740           2 :     return success;
+     741             :   }
+     742             :   /*!
+     743             :     * \brief Loads a compulsory parameter from the rosparam server.
+     744             :     *
+     745             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     746             :     * the loading process is unsuccessful (loaded_successfully() will return false).
+     747             :     * Using this method, the parameter can be loaded multiple times using the same ParamLoader instance without error.
+     748             :     *
+     749             :     * \param name          Name of the parameter in the rosparam server.
+     750             :     * \return              The loaded parameter value.
+     751             :     */
+     752             :   template <typename T>
+     753             :   T loadParamReusable2(const std::string& name)
+     754             :   {
+     755             :     const auto [ret, success] = load<T>(name, T(), COMPULSORY, REUSABLE);
+     756             :     return ret;
+     757             :   }
+     758             :   //}
+     759             : 
+     760             :   /* loadParam specializations for ros::Duration type //{ */
+     761             : 
+     762             :   /*!
+     763             :     * \brief An overload for loading ros::Duration.
+     764             :     *
+     765             :     * The duration will be loaded as a \p double, representing a number of seconds, and then converted to ros::Duration.
+     766             :     *
+     767             :     * \param name          Name of the parameter in the rosparam server.
+     768             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     769             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     770             :     * \return              true if the parameter was loaded from \p rosparam, false if the default value was used.
+     771             :     */
+     772             :   bool loadParam(const std::string& name, ros::Duration& out, const ros::Duration& default_value)
+     773             :   {
+     774             :     double secs;
+     775             :     const bool ret = loadParam<double>(name, secs, default_value.toSec());
+     776             :     out = ros::Duration(secs);
+     777             :     return ret;
+     778             :   }
+     779             : 
+     780             :   /*!
+     781             :     * \brief An overload for loading ros::Duration.
+     782             :     *
+     783             :     * The duration will be loaded as a \p double, representing a number of seconds, and then converted to ros::Duration.
+     784             :     *
+     785             :     * \param name          Name of the parameter in the rosparam server.
+     786             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     787             :     * \return              true if the parameter was loaded from \p rosparam, false if the default value was used.
+     788             :     */
+     789             :   bool loadParam(const std::string& name, ros::Duration& out)
+     790             :   {
+     791             :     double secs;
+     792             :     const bool ret = loadParam<double>(name, secs);
+     793             :     out = ros::Duration(secs);
+     794             :     return ret;
+     795             :   }
+     796             :   
+     797             :   //}
+     798             : 
+     799             :   /* loadParam specializations for std_msgs::ColorRGBA type //{ */
+     800             : 
+     801             :   /*!
+     802             :     * \brief An overload for loading std_msgs::ColorRGBA.
+     803             :     *
+     804             :     * The color will be loaded as several \p double -typed variables, representing the R, G, B and A color elements.
+     805             :     *
+     806             :     * \param name          Name of the parameter in the rosparam server.
+     807             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     808             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     809             :     * \return              true if the parameter was loaded from \p rosparam, false if the default value was used.
+     810             :     */
+     811             :   bool loadParam(const std::string& name, std_msgs::ColorRGBA& out, const std_msgs::ColorRGBA& default_value = {})
+     812             :   {
+     813             :     std_msgs::ColorRGBA res;
+     814             :     bool ret = true;
+     815             :     ret = ret & loadParam(name+"/r", res.r, default_value.r);
+     816             :     ret = ret & loadParam(name+"/g", res.g, default_value.g);
+     817             :     ret = ret & loadParam(name+"/b", res.b, default_value.b);
+     818             :     ret = ret & loadParam(name+"/a", res.a, default_value.a);
+     819             :     if (ret)
+     820             :       out = res;
+     821             :     return ret;
+     822             :   }
+     823             : 
+     824             :   /*!
+     825             :     * \brief An overload for loading std_msgs::ColorRGBA.
+     826             :     *
+     827             :     * The color will be loaded as several \p double -typed variables, representing the R, G, B and A color elements.
+     828             :     *
+     829             :     * \param name          Name of the parameter in the rosparam server.
+     830             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     831             :     * \return              The loaded parameter value.
+     832             :     */
+     833             :   std_msgs::ColorRGBA loadParam2(const std::string& name, const std_msgs::ColorRGBA& default_value = {})
+     834             :   {
+     835             :     std_msgs::ColorRGBA ret;
+     836             :     loadParam(name, ret, default_value);
+     837             :     return ret;
+     838             :   }
+     839             : 
+     840             :   //}
+     841             : 
+     842             :   /* loadParam specializations and convenience functions for Eigen dynamic matrix type //{ */
+     843             : 
+     844             :   /*!
+     845             :     * \brief An overload for loading Eigen matrices.
+     846             :     *
+     847             :     * For compulsory Eigen matrices, use loadMatrixStatic() or loadMatrixDynamic().
+     848             :     * Matrix dimensions are deduced from the provided default value.
+     849             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     850             :     * the default value is used.
+     851             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     852             :     *
+     853             :     * \param name          Name of the parameter in the rosparam server.
+     854             :     * \param out_value     Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     855             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     856             :     */
+     857             :   template <typename T>
+     858             :   void loadParam(const std::string& name, MatrixX<T>& mat, const MatrixX<T>& default_value)
+     859             :   {
+     860             :     mat = loadParam2(name, default_value);
+     861             :   }
+     862             : 
+     863             :   /*!
+     864             :     * \brief An overload for loading Eigen matrices.
+     865             :     *
+     866             :     * For compulsory Eigen matrices, use loadMatrixStatic() or loadMatrixDynamic().
+     867             :     * Matrix dimensions are deduced from the provided default value.
+     868             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     869             :     * the default value is used.
+     870             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     871             :     *
+     872             :     * \param name          Name of the parameter in the rosparam server.
+     873             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     874             :     * \return              The loaded parameter value.
+     875             :     */
+     876             :   template <typename T>
+     877             :   MatrixX<T> loadParam2(const std::string& name, const MatrixX<T>& default_value)
+     878             :   {
+     879             :     int rows = default_value.rows();
+     880             :     int cols = default_value.cols();
+     881             :     MatrixX<T> loaded;
+     882             :     loadMatrixDynamic(name, loaded, default_value, rows, cols);
+     883             :     return loaded;
+     884             :   }
+     885             :   
+     886             :   //}
+     887             : 
+     888             :   // loadMatrixStatic function for loading of static Eigen::Matrices //{
+     889             : 
+     890             :   /*!
+     891             :     * \brief Specialized method for loading compulsory Eigen matrix parameters.
+     892             :     *
+     893             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+     894             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     895             :     * the loading process is unsuccessful.
+     896             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     897             :     *
+     898             :     * \tparam rows  Expected number of rows of the matrix.
+     899             :     * \tparam cols  Expected number of columns of the matrix.
+     900             :     *
+     901             :     * \param name  Name of the parameter in the rosparam server.
+     902             :     * \param mat   Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     903             :     *
+     904             :     */
+     905             :   template <int rows, int cols, typename T>
+     906           1 :   void loadMatrixStatic(const std::string& name, Eigen::Matrix<T, rows, cols>& mat)
+     907             :   {
+     908           1 :     mat = loadMatrixStatic2<rows, cols, T>(name);
+     909           1 :   }
+     910             : 
+     911             :   /*!
+     912             :     * \brief Specialized method for loading Eigen matrix parameters with default value.
+     913             :     *
+     914             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+     915             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     916             :     * the default value is used.
+     917             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     918             :     *
+     919             :     * \tparam rows          Expected number of rows of the matrix.
+     920             :     * \tparam cols          Expected number of columns of the matrix.
+     921             :     *
+     922             :     * \param name          Name of the parameter in the rosparam server.
+     923             :     * \param mat           Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     924             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     925             :     *
+     926             :     */
+     927             :   template <int rows, int cols, typename T, typename Derived>
+     928           1 :   void loadMatrixStatic(const std::string& name, Eigen::Matrix<T, rows, cols>& mat, const Eigen::MatrixBase<Derived>& default_value)
+     929             :   {
+     930           1 :     mat = loadMatrixStatic2<rows, cols, T>(name, default_value);
+     931           1 :   }
+     932             : 
+     933             :   /*!
+     934             :     * \brief Specialized method for loading compulsory Eigen matrix parameters.
+     935             :     *
+     936             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+     937             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     938             :     * the loading process is unsuccessful.
+     939             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     940             :     *
+     941             :     * \tparam rows  Expected number of rows of the matrix.
+     942             :     * \tparam cols  Expected number of columns of the matrix.
+     943             :     *
+     944             :     * \param name  Name of the parameter in the rosparam server.
+     945             :     * \return      The loaded parameter value.
+     946             :     *
+     947             :     */
+     948             :   template <int rows, int cols, typename T = double>
+     949           3 :   Eigen::Matrix<T, rows, cols> loadMatrixStatic2(const std::string& name)
+     950             :   {
+     951           3 :     return loadMatrixStatic_internal<rows, cols, T>(name, Eigen::Matrix<T, rows, cols>::Zero(), COMPULSORY, UNIQUE);
+     952             :   }
+     953             : 
+     954             :   /*!
+     955             :     * \brief Specialized method for loading Eigen matrix parameters with default value.
+     956             :     *
+     957             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+     958             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     959             :     * the default value is used.
+     960             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     961             :     *
+     962             :     * \tparam rows          Expected number of rows of the matrix.
+     963             :     * \tparam cols          Expected number of columns of the matrix.
+     964             :     *
+     965             :     * \param name          Name of the parameter in the rosparam server.
+     966             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+     967             :     * \return              The loaded parameter value.
+     968             :     *
+     969             :     */
+     970             :   template <int rows, int cols, typename T, typename Derived>
+     971           2 :   Eigen::Matrix<T, rows, cols> loadMatrixStatic2(const std::string& name, const Eigen::MatrixBase<Derived>& default_value)
+     972             :   {
+     973           2 :     return loadMatrixStatic_internal<rows, cols, T>(name, Eigen::Matrix<T, rows, cols>(default_value), OPTIONAL, UNIQUE);
+     974             :   }
+     975             :   //}
+     976             : 
+     977             :   // loadMatrixStatic function for loading of Eigen matrices with known dimensions //{
+     978             : 
+     979             :   /*!
+     980             :     * \brief Specialized method for loading compulsory Eigen matrix parameters.
+     981             :     *
+     982             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+     983             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+     984             :     * the loading process is unsuccessful.
+     985             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+     986             :     *
+     987             :     * \param name  Name of the parameter in the rosparam server.
+     988             :     * \param mat   Reference to the variable to which the parameter value will be stored (such as a class member variable).
+     989             :     * \param rows  Expected number of rows of the matrix.
+     990             :     * \param cols  Expected number of columns of the matrix.
+     991             :     */
+     992             :   template <typename T>
+     993           1 :   void loadMatrixStatic(const std::string& name, MatrixX<T>& mat, int rows, int cols)
+     994             :   {
+     995           1 :     mat = loadMatrixStatic2<T>(name, rows, cols);
+     996           1 :   }
+     997             : 
+     998             :   /*!
+     999             :     * \brief Specialized method for loading Eigen matrix parameters with default value.
+    1000             :     *
+    1001             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1002             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1003             :     * the default value is used.
+    1004             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1005             :     *
+    1006             :     * \param name          Name of the parameter in the rosparam server.
+    1007             :     * \param mat           Reference to the variable to which the parameter value will be stored (such as a class member variable).
+    1008             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+    1009             :     * \param rows          Expected number of rows of the matrix.
+    1010             :     * \param cols          Expected number of columns of the matrix.
+    1011             :     */
+    1012             :   template <typename T, typename Derived>
+    1013           1 :   void loadMatrixStatic(const std::string& name, MatrixX<T>& mat, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
+    1014             :   {
+    1015           1 :     mat = loadMatrixStatic2<T>(name, default_value, rows, cols);
+    1016           1 :   }
+    1017             : 
+    1018             :   /*!
+    1019             :     * \brief Specialized method for loading compulsory Eigen matrix parameters.
+    1020             :     *
+    1021             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1022             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1023             :     * the loading process is unsuccessful.
+    1024             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1025             :     *
+    1026             :     * \param name  Name of the parameter in the rosparam server.
+    1027             :     * \param rows  Expected number of rows of the matrix.
+    1028             :     * \param cols  Expected number of columns of the matrix.
+    1029             :     * \return      The loaded parameter value.
+    1030             :     */
+    1031             :   template <typename T = double>
+    1032           2 :   MatrixX<T> loadMatrixStatic2(const std::string& name, int rows, int cols)
+    1033             :   {
+    1034           2 :     return loadMatrixStatic_internal(name, MatrixX<T>(), rows, cols, COMPULSORY, UNIQUE);
+    1035             :   }
+    1036             : 
+    1037             :   /*!
+    1038             :     * \brief Specialized method for loading Eigen matrix parameters with default value.
+    1039             :     *
+    1040             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1041             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1042             :     * the default value is used.
+    1043             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1044             :     *
+    1045             :     * \param name          Name of the parameter in the rosparam server.
+    1046             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+    1047             :     * \param rows          Expected number of rows of the matrix.
+    1048             :     * \param cols          Expected number of columns of the matrix.
+    1049             :     * \return              The loaded parameter value.
+    1050             :     */
+    1051             :   template <typename T, typename Derived>
+    1052           2 :   MatrixX<T> loadMatrixStatic2(const std::string& name, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
+    1053             :   {
+    1054           2 :     return loadMatrixStatic_internal(name, MatrixX<T>(default_value), rows, cols, OPTIONAL, UNIQUE);
+    1055             :   }
+    1056             :   //}
+    1057             : 
+    1058             :   // loadMatrixDynamic function for half-dynamic loading of MatrixX<T> //{
+    1059             : 
+    1060             :   /*!
+    1061             :     * \brief Specialized method for loading compulsory dynamic Eigen matrix parameters.
+    1062             :     *
+    1063             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1064             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1065             :     * the loading process is unsuccessful.
+    1066             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1067             :     *
+    1068             :     * \param name  Name of the parameter in the rosparam server.
+    1069             :     * \param mat   Reference to the variable to which the parameter value will be stored (such as a class member variable).
+    1070             :     * \param rows  Expected number of rows of the matrix (negative value indicates that the number of rows is to be deduced from the specified number of columns and the size of the loaded array).
+    1071             :     * \param cols  Expected number of columns of the matrix (negative value indicates that the number of columns is to be deduced from the specified number of rows and the size of the loaded array).
+    1072             :     */
+    1073             :   template <typename T>
+    1074           1 :   void loadMatrixDynamic(const std::string& name, MatrixX<T>& mat, int rows, int cols)
+    1075             :   {
+    1076           1 :     mat = loadMatrixDynamic2<T>(name, rows, cols);
+    1077           1 :   }
+    1078             : 
+    1079             :   /*!
+    1080             :     * \brief Specialized method for loading compulsory dynamic Eigen matrix parameters.
+    1081             :     *
+    1082             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1083             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1084             :     * the default value is used.
+    1085             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1086             :     *
+    1087             :     * \param name          Name of the parameter in the rosparam server.
+    1088             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+    1089             :     * \param mat           Reference to the variable to which the parameter value will be stored (such as a class member variable).
+    1090             :     * \param rows          Expected number of rows of the matrix (negative value indicates that the number of rows is to be deduced from the specified number of columns and the size of the loaded array).
+    1091             :     * \param cols          Expected number of columns of the matrix (negative value indicates that the number of columns is to be deduced from the specified number of rows and the size of the loaded array).
+    1092             :     */
+    1093             :   template <typename T, typename Derived>
+    1094           1 :   void loadMatrixDynamic(const std::string& name, MatrixX<T>& mat, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
+    1095             :   {
+    1096           1 :     mat = loadMatrixDynamic2<T>(name, default_value, rows, cols);
+    1097           1 :   }
+    1098             : 
+    1099             :   /*!
+    1100             :     * \brief Specialized method for loading compulsory dynamic Eigen matrix parameters.
+    1101             :     *
+    1102             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1103             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1104             :     * the loading process is unsuccessful.
+    1105             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1106             :     *
+    1107             :     * \param name  Name of the parameter in the rosparam server.
+    1108             :     * \param rows  Expected number of rows of the matrix (negative value indicates that the number of rows is to be deduced from the specified number of columns and the size of the loaded array).
+    1109             :     * \param cols  Expected number of columns of the matrix (negative value indicates that the number of columns is to be deduced from the specified number of rows and the size of the loaded array).
+    1110             :     * \return      The loaded parameter value.
+    1111             :     */
+    1112             :   template <typename T = double>
+    1113           2 :   MatrixX<T> loadMatrixDynamic2(const std::string& name, int rows, int cols)
+    1114             :   {
+    1115           2 :     return loadMatrixDynamic_internal(name, MatrixX<T>(), rows, cols, COMPULSORY, UNIQUE);
+    1116             :   }
+    1117             : 
+    1118             :   /*!
+    1119             :     * \brief Specialized method for loading compulsory dynamic Eigen matrix parameters.
+    1120             :     *
+    1121             :     * If the dimensions of the loaded matrix do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1122             :     * If the parameter with the specified name is not found on the rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1123             :     * the default value is used.
+    1124             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1125             :     *
+    1126             :     * \param name          Name of the parameter in the rosparam server.
+    1127             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+    1128             :     * \param rows          Expected number of rows of the matrix (negative value indicates that the number of rows is to be deduced from the specified number of columns and the size of the loaded array).
+    1129             :     * \param cols          Expected number of columns of the matrix (negative value indicates that the number of columns is to be deduced from the specified number of rows and the size of the loaded array).
+    1130             :     * \return              The loaded parameter value.
+    1131             :     */
+    1132             :   template <typename T, typename Derived>
+    1133           2 :   MatrixX<T> loadMatrixDynamic2(const std::string& name, const Eigen::MatrixBase<Derived>& default_value, int rows, int cols)
+    1134             :   {
+    1135           2 :     return loadMatrixDynamic_internal(name, MatrixX<T>(default_value), rows, cols, OPTIONAL, UNIQUE);
+    1136             :   }
+    1137             : 
+    1138             :   //}
+    1139             : 
+    1140             :   // loadMatrixArray function for loading of an array of MatrixX<T> with known dimensions //{
+    1141             :   /*!
+    1142             :     * \brief Specialized method for loading compulsory parameters, interpreted as an array of dynamic Eigen matrices.
+    1143             :     *
+    1144             :     * The number of rows and columns of the matrices to be loaded is specified in the \c rosparam parameter. Specifically, the \c name/rows value specifies the
+    1145             :     * number of rows, which must be common to all the loaded matrices (i.e. it is one integer >= 0), and the \c name/cols value specifies the number of columns of
+    1146             :     * each matrix (i.e. it is an array of integers > 0). The \c name/data array contains the values of the elements of the matrices and it must have length
+    1147             :     * \f$ r\sum_i c_i \f$, where \f$ r \f$ is the common number of rows and \f$ c_i \f$ is the number of columns of the \f$ i \f$-th matrix.
+    1148             :     * A typical structure of a \c yaml file, specifying the
+    1149             :     * matrix array to be loaded using this method, is
+    1150             :     *
+    1151             :     * \code{.yaml}
+    1152             :     *
+    1153             :     * matrix_array:
+    1154             :     *   rows: 3
+    1155             :     *   cols: [1, 2]
+    1156             :     *   data: [-5.0, Eigen::Dynamic0.0, 23.0,
+    1157             :     *          -5.0, Eigen::Dynamic0.0, 12.0,
+    1158             :     *           2.0,   4.0,  7.0]
+    1159             :     *
+    1160             :     * \endcode
+    1161             :     *
+    1162             :     * which will be loaded as a \c std::vector, containing one \f$ 3\times 1 \f$ matrix and one \f$ 3\times 2 \f$ matrix.
+    1163             :     *
+    1164             :     * If the dimensions of the loaded matrices do not match the specified number of rows and columns, the loading process is unsuccessful (loaded_successfully() will return false).
+    1165             :     * If the parameter with the specified name is not found on the \c rosparam server (e.g. because it is not specified in the launchfile or yaml config file),
+    1166             :     * the loading process is unsuccessful.
+    1167             :     * Using this method, the parameter can only be loaded once using the same ParamLoader instance without error.
+    1168             :     *
+    1169             :     * \param name  Name of the parameter in the rosparam server.
+    1170             :     * \param mat   Reference to the variable to which the parameter value will be stored (such as a class member variable).
+    1171             :     *
+    1172             :     */
+    1173             :   template <typename T>
+    1174           1 :   void loadMatrixArray(const std::string& name, std::vector<MatrixX<T>>& mat)
+    1175             :   {
+    1176           1 :     mat = loadMatrixArray2<double>(name);
+    1177           1 :   }
+    1178             : 
+    1179             :   /*!
+    1180             :     * \brief Specialized method for loading compulsory parameters, interpreted as an array of dynamic Eigen matrices.
+    1181             :     *
+    1182             :     * This overload of the loadMatrixArray() method takes a default value for the parameter, which is used in case a \c rosparam with the specified name is not
+    1183             :     * found in the \c rosparam server, instead of causing an unsuccessful load. This makes specifying the parameter value in the \c rosparam server optional.
+    1184             :     *
+    1185             :     * \param name           Name of the parameter in the rosparam server.
+    1186             :     * \param mat            Reference to the variable to which the parameter value will be stored (such as a class member variable).
+    1187             :     * \param default_value  The default value to be used in case the parameter is not found on the \c rosparam server.
+    1188             :     *
+    1189             :     */
+    1190             :   template <typename T>
+    1191           1 :   void loadMatrixArray(const std::string& name, std::vector<MatrixX<T>>& mat, const std::vector<MatrixX<T>>& default_value)
+    1192             :   {
+    1193           1 :     mat = loadMatrixArray2(name, default_value);
+    1194           1 :   }
+    1195             : 
+    1196             :   /*!
+    1197             :     * \brief Specialized method for loading compulsory parameters, interpreted as an array of dynamic Eigen matrices.
+    1198             :     *
+    1199             :     * This method works in the same way as the loadMatrixArray() method for compulsory parameters, except that the loaded
+    1200             :     * parameter is returned and not stored in the reference parameter.
+    1201             :     *
+    1202             :     * \param name           Name of the parameter in the rosparam server.
+    1203             :     * \returns              The loaded parameter or a default constructed object of the respective type.
+    1204             :     *
+    1205             :     */
+    1206             :   template <typename T = double>
+    1207           3 :   std::vector<MatrixX<T>> loadMatrixArray2(const std::string& name)
+    1208             :   {
+    1209           3 :     return loadMatrixArray_internal(name, std::vector<MatrixX<T>>(), COMPULSORY, UNIQUE);
+    1210             :   }
+    1211             : 
+    1212             :   /*!
+    1213             :     * \brief Specialized method for loading compulsory parameters, interpreted as an array of dynamic Eigen matrices.
+    1214             :     *
+    1215             :     * This method works in the same way as the loadMatrixArray() method for optional parameters, except that the loaded
+    1216             :     * parameter is returned and not stored in the reference parameter.
+    1217             :     *
+    1218             :     * \param name           Name of the parameter in the rosparam server.
+    1219             :     * \param default_value  The default value to be used in case the parameter is not found on the \c rosparam server.
+    1220             :     * \returns              The loaded parameter or the default value.
+    1221             :     *
+    1222             :     */
+    1223             :   template <typename T>
+    1224           2 :   std::vector<MatrixX<T>> loadMatrixArray2(const std::string& name, const std::vector<MatrixX<T>>& default_value)
+    1225             :   {
+    1226           2 :     return loadMatrixArray_internal(name, default_value, OPTIONAL, UNIQUE);
+    1227             :   }
+    1228             :   //}
+    1229             : 
+    1230             :   //}
+    1231             : 
+    1232             : };
+    1233             : //}
+    1234             : 
+    1235             :   /*!
+    1236             :     * \brief An overload for loading ros::Duration.
+    1237             :     *
+    1238             :     * The duration will be loaded as a \p double, representing a number of seconds, and then converted to ros::Duration.
+    1239             :     *
+    1240             :     * \param name          Name of the parameter in the rosparam server.
+    1241             :     * \param default_value This value will be used if the parameter name is not found in the rosparam server.
+    1242             :     * \return              The loaded parameter value.
+    1243             :     */
+    1244             :   template <>
+    1245             :   ros::Duration ParamLoader::loadParam2<ros::Duration>(const std::string& name, const ros::Duration& default_value);
+    1246             : 
+    1247             :   /*!
+    1248             :     * \brief An overload for loading ros::Duration.
+    1249             :     *
+    1250             :     * The duration will be loaded as a \p double, representing a number of seconds, and then converted to ros::Duration.
+    1251             :     *
+    1252             :     * \param name          Name of the parameter in the rosparam server.
+    1253             :     * \return              The loaded parameter value.
+    1254             :     */
+    1255             :   template <>
+    1256             :   ros::Duration ParamLoader::loadParam2<ros::Duration>(const std::string& name);
+    1257             : 
+    1258             : }  // namespace mrs_lib
+    1259             : 
+    1260             : #endif  // PARAM_LOADER_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/publisher_handler.h.func-sort-c.html b/mrs_lib/include/mrs_lib/publisher_handler.h.func-sort-c.html new file mode 100644 index 0000000000..deca91f32c --- /dev/null +++ b/mrs_lib/include/mrs_lib/publisher_handler.h.func-sort-c.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/publisher_handler.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - publisher_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:33100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16PublisherHandlerIN8std_msgs6Int64_ISaIvEEEED2Ev2
_ZN7mrs_lib21PublisherHandler_implIN8std_msgs6Int64_ISaIvEEEED2Ev2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/publisher_handler.h.func.html b/mrs_lib/include/mrs_lib/publisher_handler.h.func.html new file mode 100644 index 0000000000..307593780c --- /dev/null +++ b/mrs_lib/include/mrs_lib/publisher_handler.h.func.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/publisher_handler.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - publisher_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:33100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16PublisherHandlerIN8std_msgs6Int64_ISaIvEEEED2Ev2
_ZN7mrs_lib21PublisherHandler_implIN8std_msgs6Int64_ISaIvEEEED2Ev2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/publisher_handler.h.gcov.html b/mrs_lib/include/mrs_lib/publisher_handler.h.gcov.html new file mode 100644 index 0000000000..1e97f72b88 --- /dev/null +++ b/mrs_lib/include/mrs_lib/publisher_handler.h.gcov.html @@ -0,0 +1,248 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/publisher_handler.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - publisher_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:33100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /**  \file
+       2             :      \brief Defines PublisherHandler and related convenience classes for upgrading the ROS publisher
+       3             :      \author Tomas Baca - tomas.baca@fel.cvut.cz
+       4             :  */
+       5             : #ifndef PUBLISHER_HANDLER_H
+       6             : #define PUBLISHER_HANDLER_H
+       7             : 
+       8             : #include <ros/ros.h>
+       9             : #include <ros/package.h>
+      10             : 
+      11             : #include <atomic>
+      12             : #include <string>
+      13             : #include <mutex>
+      14             : 
+      15             : namespace mrs_lib
+      16             : {
+      17             : 
+      18             : /* class PublisherHandler_impl //{ */
+      19             : 
+      20             : /**
+      21             :  * @brief implementation of the publisher handler
+      22             :  */
+      23             : template <class TopicType>
+      24             : class PublisherHandler_impl {
+      25             : 
+      26             : public:
+      27             :   /**
+      28             :    * @brief default constructor
+      29             :    */
+      30             :   PublisherHandler_impl(void);
+      31             : 
+      32             :   /**
+      33             :    * @brief default destructor
+      34             :    */
+      35           2 :   ~PublisherHandler_impl(void){};
+      36             : 
+      37             :   /**
+      38             :    * @brief constructor
+      39             :    *
+      40             :    * @param nh ROS node handler
+      41             :    * @param address topic address
+      42             :    * @param buffer_size buffer size
+      43             :    * @param latch latching
+      44             :    */
+      45             :   PublisherHandler_impl(ros::NodeHandle& nh, const std::string& address, const unsigned int& buffer_size = 1, const bool& latch = false,
+      46             :                         const double& rate = 0.0);
+      47             : 
+      48             :   /**
+      49             :    * @brief publish message
+      50             :    *
+      51             :    * @param msg data
+      52             :    *
+      53             :    */
+      54             :   void publish(const TopicType& msg);
+      55             : 
+      56             :   /**
+      57             :    * @brief publish message, boost ptr overload
+      58             :    *
+      59             :    * @param msg
+      60             :    */
+      61             :   void publish(const boost::shared_ptr<TopicType>& msg);
+      62             : 
+      63             :   /**
+      64             :    * @brief publish message, boost const ptr overload
+      65             :    *
+      66             :    * @param msg
+      67             :    */
+      68             :   void publish(const boost::shared_ptr<TopicType const>& msg);
+      69             : 
+      70             :   /**
+      71             :    * @brief get number of subscribers
+      72             :    *
+      73             :    * @return the number of subscribers
+      74             :    */
+      75             :   unsigned int getNumSubscribers(void);
+      76             : 
+      77             : private:
+      78             :   ros::Publisher    publisher_;
+      79             :   std::mutex        mutex_publisher_;
+      80             :   std::atomic<bool> publisher_initialized_;
+      81             : 
+      82             :   bool      throttle_ = false;
+      83             :   double    throttle_min_dt_;
+      84             :   ros::Time last_time_published_;
+      85             : };
+      86             : 
+      87             : //}
+      88             : 
+      89             : /* class PublisherHandler //{ */
+      90             : 
+      91             : /**
+      92             :  * @brief user wrapper of the publisher handler implementation
+      93             :  */
+      94             : template <class TopicType>
+      95             : class PublisherHandler {
+      96             : 
+      97             : public:
+      98             :   /**
+      99             :    * @brief generic constructor
+     100             :    */
+     101             :   PublisherHandler(void){};
+     102             : 
+     103             :   /**
+     104             :    * @brief generic destructor
+     105             :    */
+     106           2 :   ~PublisherHandler(void){};
+     107             : 
+     108             :   /**
+     109             :    * @brief operator=
+     110             :    *
+     111             :    * @param other
+     112             :    *
+     113             :    * @return
+     114             :    */
+     115             :   PublisherHandler& operator=(const PublisherHandler& other);
+     116             : 
+     117             :   /**
+     118             :    * @brief copy constructor
+     119             :    *
+     120             :    * @param other
+     121             :    */
+     122             :   PublisherHandler(const PublisherHandler& other);
+     123             : 
+     124             :   /**
+     125             :    * @brief constructor
+     126             :    *
+     127             :    * @param nh ROS node handler
+     128             :    * @param address topic address
+     129             :    * @param buffer_size buffer size
+     130             :    * @param latch latching
+     131             :    */
+     132           2 :   PublisherHandler(ros::NodeHandle& nh, const std::string& address, const unsigned int& buffer_size = 1, const bool& latch = false, const double& rate = 0);
+     133             : 
+     134             :   /**
+     135             :    * @brief publish message
+     136             :    *
+     137             :    * @param msg
+     138             :    */
+     139             :   void publish(const TopicType& msg);
+     140             : 
+     141             :   /**
+     142             :    * @brief publish message, boost ptr overload
+     143             :    *
+     144             :    * @param msg
+     145             :    */
+     146             :   void publish(const boost::shared_ptr<TopicType>& msg);
+     147             : 
+     148             :   /**
+     149             :    * @brief publish message, boost const ptr overload
+     150             :    *
+     151             :    * @param msg
+     152             :    */
+     153             :   void publish(const boost::shared_ptr<TopicType const>& msg);
+     154             : 
+     155             :   /**
+     156             :    * @brief get number of subscribers
+     157             :    *
+     158             :    * @return the number of subscribers
+     159             :    */
+     160             :   unsigned int getNumSubscribers(void);
+     161             : 
+     162             : private:
+     163             :   std::shared_ptr<PublisherHandler_impl<TopicType>> impl_;
+     164             : };
+     165             : 
+     166             : //}
+     167             : 
+     168             : }  // namespace mrs_lib
+     169             : 
+     170             : #include <mrs_lib/impl/publisher_handler.hpp>
+     171             : 
+     172             : #endif  // PUBLISHER_HANDLER_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/repredictor.h.func-sort-c.html b/mrs_lib/include/mrs_lib/repredictor.h.func-sort-c.html new file mode 100644 index 0000000000..69a06e9d86 --- /dev/null +++ b/mrs_lib/include/mrs_lib/repredictor.h.func-sort-c.html @@ -0,0 +1,152 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/repredictor.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - repredictor.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:10011190.1 %
Date:2023-11-29 14:09:54Functions:2020100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EEC2ERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS5_IdLi2ELi2ELi0ELi2ELi2EEERKNS5_IdLi1ELi1ELi0ELi1ELi1EEESB_RKN3ros4TimeERKSt10shared_ptrIS2_Ej1
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE6info_tC2ERKN3ros4TimeE2
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EEC2ERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS5_IdLi2ELi2ELi0ELi2ELi2EEERKNS5_IdLi1ELi1ELi0ELi1ELi1EEESB_RKN3ros4TimeERKSt10shared_ptrIS2_Ej2
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE14addInputChangeILb1EEENSt9enable_ifIXT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKN3ros4TimeERKSt10shared_ptrIS2_E91
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE14addMeasurementILb0EEENSt9enable_ifIXntT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESC_RKN3ros4TimeERKSt10shared_ptrIS2_ERKd100
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_tC2ERKN3ros4TimeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESD_RKSt10shared_ptrIS2_ERKS4_RKi100
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE9predictToILb0EEENSt9enable_ifIXntT_ENS_12KalmanFilterILi2ELi1ELi1EE10statecov_tEE4typeERKN3ros4TimeE102
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE23addInputChangeWithNoiseILb0EEENSt9enable_ifIXntT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS9_IdLi2ELi2ELi0ELi2ELi2EEERKN3ros4TimeERKSt10shared_ptrIS2_E200
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_tC2ERKN3ros4TimeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNSA_IdLi2ELi2ELi0ELi2ELi2EEERKSt10shared_ptrIS2_E200
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE23addInputChangeWithNoiseILb1EEENSt9enable_ifIXT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS9_IdLi2ELi2ELi0ELi2ELi2EEERKN3ros4TimeERKSt10shared_ptrIS2_E216
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE11correctFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tE292
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE14addMeasurementILb1EEENSt9enable_ifIXT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESC_RKN3ros4TimeERKSt10shared_ptrIS2_ERKd292
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE7addInfoERKNS3_6info_tERKN5boost10cb_details8iteratorINS7_15circular_bufferIS4_SaIS4_EEENS8_15nonconst_traitsINS8_16allocator_traitsISB_EEEEEE300
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE11predictFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tERKN3ros4TimeESF_584
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE9predictToILb1EEENSt9enable_ifIXT_ENS_12KalmanFilterILi2ELi1ELi1EE10statecov_tEE4typeERKN3ros4TimeE584
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_tC2ERKN3ros4TimeE636
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE7earlierERKNS3_6info_tES6_2047
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE11correctFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tE5150
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_t11updateUsingERKS4_5639
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE11predictFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tERKN3ros4TimeESF_15455
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/repredictor.h.func.html b/mrs_lib/include/mrs_lib/repredictor.h.func.html new file mode 100644 index 0000000000..d3069062bc --- /dev/null +++ b/mrs_lib/include/mrs_lib/repredictor.h.func.html @@ -0,0 +1,152 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/repredictor.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - repredictor.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:10011190.1 %
Date:2023-11-29 14:09:54Functions:2020100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE11correctFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tE5150
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE11predictFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tERKN3ros4TimeESF_15455
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE14addMeasurementILb0EEENSt9enable_ifIXntT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESC_RKN3ros4TimeERKSt10shared_ptrIS2_ERKd100
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE23addInputChangeWithNoiseILb0EEENSt9enable_ifIXntT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS9_IdLi2ELi2ELi0ELi2ELi2EEERKN3ros4TimeERKSt10shared_ptrIS2_E200
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_t11updateUsingERKS4_5639
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_tC2ERKN3ros4TimeE636
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_tC2ERKN3ros4TimeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNSA_IdLi2ELi2ELi0ELi2ELi2EEERKSt10shared_ptrIS2_E200
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE6info_tC2ERKN3ros4TimeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESD_RKSt10shared_ptrIS2_ERKS4_RKi100
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE7addInfoERKNS3_6info_tERKN5boost10cb_details8iteratorINS7_15circular_bufferIS4_SaIS4_EEENS8_15nonconst_traitsINS8_16allocator_traitsISB_EEEEEE300
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE7earlierERKNS3_6info_tES6_2047
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EE9predictToILb0EEENSt9enable_ifIXntT_ENS_12KalmanFilterILi2ELi1ELi1EE10statecov_tEE4typeERKN3ros4TimeE102
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb0EEC2ERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS5_IdLi2ELi2ELi0ELi2ELi2EEERKNS5_IdLi1ELi1ELi0ELi1ELi1EEESB_RKN3ros4TimeERKSt10shared_ptrIS2_Ej1
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE11correctFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tE292
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE11predictFromERKNS_12KalmanFilterILi2ELi1ELi1EE10statecov_tERKNS3_6info_tERKN3ros4TimeESF_584
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE14addInputChangeILb1EEENSt9enable_ifIXT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKN3ros4TimeERKSt10shared_ptrIS2_E91
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE14addMeasurementILb1EEENSt9enable_ifIXT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEESC_RKN3ros4TimeERKSt10shared_ptrIS2_ERKd292
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE23addInputChangeWithNoiseILb1EEENSt9enable_ifIXT_EvE4typeERKN5Eigen6MatrixIdLi1ELi1ELi0ELi1ELi1EEERKNS9_IdLi2ELi2ELi0ELi2ELi2EEERKN3ros4TimeERKSt10shared_ptrIS2_E216
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE6info_tC2ERKN3ros4TimeE2
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EE9predictToILb1EEENSt9enable_ifIXT_ENS_12KalmanFilterILi2ELi1ELi1EE10statecov_tEE4typeERKN3ros4TimeE584
_ZN7mrs_lib11RepredictorINS_10varstepLKFILi2ELi1ELi1EEELb1EEC2ERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEERKNS5_IdLi2ELi2ELi0ELi2ELi2EEERKNS5_IdLi1ELi1ELi0ELi1ELi1EEESB_RKN3ros4TimeERKSt10shared_ptrIS2_Ej2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/repredictor.h.gcov.html b/mrs_lib/include/mrs_lib/repredictor.h.gcov.html new file mode 100644 index 0000000000..8b0249da89 --- /dev/null +++ b/mrs_lib/include/mrs_lib/repredictor.h.gcov.html @@ -0,0 +1,629 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/repredictor.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - repredictor.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:10011190.1 %
Date:2023-11-29 14:09:54Functions:2020100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef REPREDICTOR_H
+       2             : #define REPREDICTOR_H
+       3             : 
+       4             : #include <Eigen/Dense>
+       5             : #include <boost/circular_buffer.hpp>
+       6             : #include <std_msgs/Time.h>
+       7             : #include <functional>
+       8             : #include <ros/ros.h>
+       9             : #include <mrs_lib/utils.h>
+      10             : 
+      11             : namespace mrs_lib
+      12             : {
+      13             :   /**
+      14             :    * \brief Implementation of the Repredictor for fusing measurements with variable delays.
+      15             :    *
+      16             :    * A standard state-space system model is assumed for the repredictor with system inputs and measurements,
+      17             :    * generated from the system state vector. The inputs and measurements may be delayed with varying durations (an older measurement may become available after
+      18             :    * a newer one). A typical use-case scenario is when you have one "fast" but imprecise sensor and one "slow" but precise sensor and you want to use them both
+      19             :    * to get a good prediction (eg. height from the Garmin LiDAR, which comes at 100Hz, and position from a SLAM, which comes at 10Hz with a long delay). If the
+      20             :    * slow sensor is significantly slower than the fast one, fusing its measurement at the time it arrives without taking into account the sensor's delay may
+      21             :    * significantly bias your latest estimate.
+      22             :    *
+      23             :    * To accomodate this, the Repredictor keeps a buffer of N last inputs and measurements (N is specified
+      24             :    * in the constructor). This buffer is then used to re-predict the desired state to a specific time, as
+      25             :    * requested by the user. Note that the re-prediction is evaluated in a lazy manner only when the user requests it,
+      26             :    * so it goes through the whole history buffer every time a prediction is requested.
+      27             :    *
+      28             :    * The Repredictor utilizes a fusion Model (specified as the template parameter), which should implement
+      29             :    * the predict() and correct() methods. This Model is used for fusing the system inputs and measurements
+      30             :    * as well as for predictions. Typically, this Model will be some kind of a Kalman Filter (LKF, UKF etc.).
+      31             :    * \note The Model should be able to accomodate predictions with varying time steps in order for
+      32             :    * the Repredictor to work correctly (see eg. the varstepLKF class).
+      33             :    *
+      34             :    * \tparam Model                  the prediction and correction model (eg. a Kalman Filter).
+      35             :    * \tparam disable_reprediction   if true, reprediction is disabled and the class will act like a dumb LKF (for evaluation purposes).
+      36             :    *
+      37             :    */
+      38             :   template <class Model, bool disable_reprediction=false>
+      39             :   class Repredictor
+      40             :   {
+      41             :   public:
+      42             :     /* states, inputs etc. definitions (typedefs, constants etc) //{ */
+      43             : 
+      44             :     using x_t = typename Model::x_t;                  /*!< \brief State vector type \f$n \times 1\f$ */
+      45             :     using u_t = typename Model::u_t;                  /*!< \brief Input vector type \f$m \times 1\f$ */
+      46             :     using z_t = typename Model::z_t;                  /*!< \brief Measurement vector type \f$p \times 1\f$ */
+      47             :     using P_t = typename Model::P_t;                  /*!< \brief State uncertainty covariance matrix type \f$n \times n\f$ */
+      48             :     using R_t = typename Model::R_t;                  /*!< \brief Measurement noise covariance matrix type \f$p \times p\f$ */
+      49             :     using Q_t = typename Model::Q_t;                  /*!< \brief Process noise covariance matrix type \f$n \times n\f$ */
+      50             :     using statecov_t = typename Model::statecov_t;    /*!< \brief Helper struct for passing around the state and its covariance in one variable */
+      51             :     using ModelPtr = typename std::shared_ptr<Model>; /*!< \brief Shorthand type for a shared pointer-to-Model */
+      52             : 
+      53             :     //}
+      54             : 
+      55             :     /* predictTo() method //{ */
+      56             :     /*!
+      57             :      * \brief Estimates the system state and covariance matrix at the specified time.
+      58             :      *
+      59             :      * The measurement and system input histories are used to estimate the state vector and
+      60             :      * covariance matrix values at the specified time, which are returned.
+      61             :      *
+      62             :      * \param to_stamp   The desired time at which the state vector and covariance matrix should be estimated.
+      63             :      * \return           Returns the estimated state vector and covariance matrix in a single struct.
+      64             :      *
+      65             :      */
+      66             :     template<bool check=disable_reprediction>
+      67         102 :     std::enable_if_t<!check, statecov_t> predictTo(const ros::Time& to_stamp)
+      68             :     {
+      69         102 :       assert(!m_history.empty());
+      70         102 :       auto hist_it = std::begin(m_history);
+      71         102 :       if (hist_it->is_measurement)
+      72             :       {
+      73             :         // if the first history point is measurement, don't use it for correction (to prevent it from being used twice)
+      74           0 :         hist_it->is_measurement = false;
+      75             :       }
+      76             :       // cur_stamp corresponds to the time point of cur_sc estimation
+      77         102 :       auto cur_stamp = hist_it->stamp;
+      78             :       // cur_sc is the current state and covariance estimate
+      79         102 :       auto cur_sc = m_sc;
+      80       15353 :       do
+      81             :       {
+      82       15455 :         cur_sc.stamp = hist_it->stamp;
+      83             :         // do the correction if current history point is a measurement
+      84       15455 :         if ((hist_it->is_measurement))
+      85        5150 :           cur_sc = correctFrom(cur_sc, *hist_it);
+      86             : 
+      87             :         // decide whether to predict to the next history point or straight to the desired stamp already
+      88             :         // (whichever comes sooner or directly to the desired stamp if no further history point is available)
+      89       15455 :         ros::Time next_stamp = to_stamp;
+      90       15455 :         if ((hist_it + 1) != std::end(m_history) && (hist_it + 1)->stamp <= to_stamp)
+      91       15353 :           next_stamp = (hist_it + 1)->stamp;
+      92             : 
+      93             :         // do the prediction
+      94       15455 :         cur_sc = predictFrom(cur_sc, *hist_it, cur_stamp, next_stamp);
+      95       15455 :         cur_stamp = next_stamp;
+      96             : 
+      97             :         // increment the history pointer
+      98       15455 :         hist_it++;
+      99       15455 :       } while (hist_it != std::end(m_history) && hist_it->stamp <= to_stamp);
+     100         102 :       cur_sc.stamp = to_stamp;
+     101         204 :       return cur_sc;
+     102             :     }
+     103             : 
+     104             :     /*!
+     105             :      * \brief Estimates the system state and covariance matrix at the specified time.
+     106             :      *
+     107             :      * The measurement and system input histories are used to estimate the state vector and
+     108             :      * covariance matrix values at the specified time, which are returned.
+     109             :      *
+     110             :      * \param to_stamp   The desired time at which the state vector and covariance matrix should be estimated.
+     111             :      * \return           Returns the estimated state vector and covariance matrix in a single struct.
+     112             :      *
+     113             :      * \note This is the variant of the method when reprediction is disabled and will function like a dumb LKF.
+     114             :      *
+     115             :      */
+     116             :     template<bool check=disable_reprediction>
+     117         584 :     std::enable_if_t<check, statecov_t> predictTo(const ros::Time& to_stamp)
+     118             :     {
+     119         584 :       assert(!m_history.empty());
+     120         584 :       const auto& info = m_history.front();
+     121         584 :       auto sc = predictFrom(m_sc, info, info.stamp, to_stamp);
+     122         584 :       sc.stamp = to_stamp;
+     123         584 :       return sc;
+     124             :     }
+     125             :     //}
+     126             : 
+     127             :     /* addInputChangeWithNoise() method //{ */
+     128             :     /*!
+     129             :      * \brief Adds one system input to the history buffer, removing the oldest element in the buffer if it is full.
+     130             :      *
+     131             :      * \param u      The system input vector to be added.
+     132             :      * \param Q      The process noise covariance matrix.
+     133             :      * \param stamp  Time stamp of the input vector and covariance matrix.
+     134             :      * \param model  Optional pointer to a specific Model to be used with this input (eg. mapping it to different states). If it equals to nullptr, the default
+     135             :      * model specified in the constructor will be used.
+     136             :      *
+     137             :      * \note The system input vector will not be added if it is older than the oldest element in the history buffer.
+     138             :      *
+     139             :      */
+     140             :     template<bool check=disable_reprediction>
+     141         200 :     std::enable_if_t<!check> addInputChangeWithNoise(const u_t& u, const Q_t& Q, const ros::Time& stamp, const ModelPtr& model = nullptr)
+     142             :     {
+     143         400 :       const info_t info(stamp, u, Q, model);
+     144             :       // find the next point in the history buffer
+     145         200 :       const auto next_it = std::lower_bound(std::begin(m_history), std::end(m_history), info, &Repredictor<Model>::earlier);
+     146             :       // add the point to the history buffer
+     147         200 :       const auto added = addInfo(info, next_it);
+     148             :       // update all measurements following the newly added system input up to the next system input
+     149         200 :       if (added != std::end(m_history))
+     150        5739 :         for (auto it = added + 1; it != std::end(m_history) && it->is_measurement; it++)
+     151        5539 :           it->updateUsing(info);
+     152         200 :     }
+     153             : 
+     154             :     /*!
+     155             :      * \brief Adds one system input to the history buffer, removing the oldest element in the buffer if it is full.
+     156             :      *
+     157             :      * \param u      The system input vector to be added.
+     158             :      * \param Q      The process noise covariance matrix.
+     159             :      * \param stamp  Time stamp of the input vector and covariance matrix.
+     160             :      * \param model  Optional pointer to a specific Model to be used with this input (eg. mapping it to different states). If it equals to nullptr, the default
+     161             :      * model specified in the constructor will be used.
+     162             :      *
+     163             :      * \note This is the variant of the method when reprediction is disabled and will function like a dumb LKF.
+     164             :      *
+     165             :      */
+     166             :     template<bool check=disable_reprediction>
+     167         216 :     std::enable_if_t<check> addInputChangeWithNoise(const u_t& u, const Q_t& Q, [[maybe_unused]] const ros::Time& stamp, const ModelPtr& model = nullptr)
+     168             :     {
+     169         216 :       if (m_history.empty())
+     170           2 :         m_history.push_back({stamp});
+     171         216 :       m_history.front().u = u;
+     172         216 :       m_history.front().Q = Q;
+     173         216 :       m_history.front().stamp = stamp;
+     174         216 :       m_history.front().predict_model = model;
+     175         216 :     }
+     176             :     //}
+     177             : 
+     178             :     /* addInputChange() method //{ */
+     179             :     /*!
+     180             :      * \brief Adds one system input to the history buffer, removing the oldest element in the buffer if it is full.
+     181             :      *
+     182             :      * \param u      The system input vector to be added.
+     183             :      * \param stamp  Time stamp of the input vector and covariance matrix.
+     184             :      * \param model  Optional pointer to a specific Model to be used with this input (eg. mapping it to different states). If it equals to nullptr, the default
+     185             :      * model specified in the constructor will be used.
+     186             :      *
+     187             :      * \note The system input vector will not be added if it is older than the oldest element in the history buffer.
+     188             :      *
+     189             :      */
+     190             :     template<bool check=disable_reprediction>
+     191             :     std::enable_if_t<!check> addInputChange(const u_t& u, const ros::Time& stamp, const ModelPtr& model = nullptr)
+     192             :     {
+     193             :       assert(!m_history.empty());
+     194             :       // find the next point in the history buffer
+     195             :       const auto next_it = std::lower_bound(std::begin(m_history), std::end(m_history), stamp, &Repredictor<Model>::earlier);
+     196             :       // get the previous history point (or the first one to avoid out of bounds)
+     197             :       const auto prev_it = next_it == std::begin(m_history) ? next_it : next_it - 1;
+     198             :       // initialize a new history info point
+     199             :       const info_t info(stamp, u, prev_it->Q, model);
+     200             :       // add the point to the history buffer
+     201             :       const auto added = addInfo(info, next_it);
+     202             :       // update all measurements following the newly added system input up to the next system input
+     203             :       if (added != std::end(m_history))
+     204             :         for (auto it = added + 1; it != std::end(m_history) && it->is_measurement; it++)
+     205             :           it->updateUsing(info);
+     206             :     }
+     207             : 
+     208             :     /*!
+     209             :      * \brief Adds one system input to the history buffer, removing the oldest element in the buffer if it is full.
+     210             :      *
+     211             :      * \param u      The system input vector to be added.
+     212             :      * \param stamp  Time stamp of the input vector and covariance matrix.
+     213             :      * \param model  Optional pointer to a specific Model to be used with this input (eg. mapping it to different states). If it equals to nullptr, the default
+     214             :      * model specified in the constructor will be used.
+     215             :      *
+     216             :      * \note This is the variant of the method when reprediction is disabled and will function like a dumb LKF.
+     217             :      *
+     218             :      */
+     219             :     template<bool check=disable_reprediction>
+     220          91 :     std::enable_if_t<check> addInputChange(const u_t& u, [[maybe_unused]] const ros::Time& stamp, const ModelPtr& model = nullptr)
+     221             :     {
+     222          91 :       if (m_history.empty())
+     223           0 :         m_history.push_back({stamp});
+     224          91 :       m_history.front().u = u;
+     225          91 :       m_history.front().stamp = stamp;
+     226          91 :       m_history.front().predict_model = model;
+     227          91 :     }
+     228             :     //}
+     229             : 
+     230             :     /* addProcessNoiseChange() method //{ */
+     231             :     /*!
+     232             :      * \brief Adds one system input to the history buffer, removing the oldest element in the buffer if it is full.
+     233             :      *
+     234             :      * \param Q      The process noise covariance matrix.
+     235             :      * \param stamp  Time stamp of the input vector and covariance matrix.
+     236             :      * \param model  Optional pointer to a specific Model to be used with this covariance matrix (eg. mapping it to different states). If it equals to nullptr,
+     237             :      * the default model specified in the constructor will be used.
+     238             :      *
+     239             :      * \note The new element will not be added if it is older than the oldest element in the history buffer.
+     240             :      *
+     241             :      */
+     242             :     template<bool check=disable_reprediction>
+     243             :     std::enable_if_t<!check> addProcessNoiseChange(const Q_t& Q, const ros::Time& stamp, const ModelPtr& model = nullptr)
+     244             :     {
+     245             :       assert(!m_history.empty());
+     246             :       // find the next point in the history buffer
+     247             :       const auto next_it = std::lower_bound(std::begin(m_history), std::end(m_history), stamp, &Repredictor<Model>::earlier);
+     248             :       // get the previous history point (or the first one to avoid out of bounds)
+     249             :       const auto prev_it = next_it == std::begin(m_history) ? next_it : next_it - 1;
+     250             :       // initialize a new history info point
+     251             :       const info_t info(stamp, prev_it->u, Q, model);
+     252             :       // add the point to the history buffer
+     253             :       const auto added = addInfo(info, next_it);
+     254             :       // update all measurements following the newly added system input up to the next system input
+     255             :       if (added != std::end(m_history))
+     256             :         for (auto it = added + 1; it != std::end(m_history) && it->is_measurement; it++)
+     257             :           it->updateUsing(info);
+     258             :     }
+     259             : 
+     260             :     /*!
+     261             :      * \brief Adds one system input to the history buffer, removing the oldest element in the buffer if it is full.
+     262             :      *
+     263             :      * \param Q      The process noise covariance matrix.
+     264             :      * \param stamp  Time stamp of the input vector and covariance matrix.
+     265             :      * \param model  Optional pointer to a specific Model to be used with this covariance matrix (eg. mapping it to different states). If it equals to nullptr,
+     266             :      * the default model specified in the constructor will be used.
+     267             :      *
+     268             :      * \note This is the variant of the method when reprediction is disabled and will function like a dumb LKF.
+     269             :      *
+     270             :      */
+     271             :     template<bool check=disable_reprediction>
+     272             :     std::enable_if_t<check> addProcessNoiseChange(const Q_t& Q, [[maybe_unused]] const ros::Time& stamp, const ModelPtr& model = nullptr)
+     273             :     {
+     274             :       if (m_history.empty())
+     275             :         m_history.push_back({stamp});
+     276             :       m_history.front().Q = Q;
+     277             :       m_history.front().stamp = stamp;
+     278             :       m_history.front().predict_model = model;
+     279             :     }
+     280             :     //}
+     281             : 
+     282             :     /* addMeasurement() method //{ */
+     283             :     /*!
+     284             :      * \brief Adds one measurement to the history buffer, removing the oldest element in the buffer if it is full.
+     285             :      *
+     286             :      * \param z      The measurement vector to be added.
+     287             :      * \param R      The measurement noise covariance matrix, corresponding to the measurement vector.
+     288             :      * \param stamp  Time stamp of the measurement vector and covariance matrix.
+     289             :      * \param model  Optional pointer to a specific Model to be used with this measurement (eg. mapping it from different states). If it equals to nullptr, the
+     290             :      * default model specified in the constructor will be used.
+     291             :      *
+     292             :      * \note The measurement vector will not be added if it is older than the oldest element in the history buffer.
+     293             :      *
+     294             :      */
+     295             :     template<bool check=disable_reprediction>
+     296         100 :     std::enable_if_t<!check> addMeasurement(const z_t& z, const R_t& R, const ros::Time& stamp, const ModelPtr& model = nullptr, const double& meas_id = -1)
+     297             :     {
+     298         100 :       assert(!m_history.empty());
+     299             :       // helper variable for searching of the next point in the history buffer
+     300         100 :       const auto next_it = std::lower_bound(std::begin(m_history), std::end(m_history), stamp, &Repredictor<Model>::earlier);
+     301             :       // get the previous history point (or the first one to avoid out of bounds)
+     302         100 :       const auto prev_it = next_it == std::begin(m_history) ? next_it : next_it - 1;
+     303             :       // initialize a new history info point
+     304         100 :       const info_t info(stamp, z, R, model, *prev_it, meas_id);
+     305             :       // add the point to the history buffer
+     306         100 :       addInfo(info, next_it);
+     307         100 :     }
+     308             : 
+     309             :     /*!
+     310             :      * \brief Adds one measurement to the history buffer, removing the oldest element in the buffer if it is full.
+     311             :      *
+     312             :      * \param z      The measurement vector to be added.
+     313             :      * \param R      The measurement noise covariance matrix, corresponding to the measurement vector.
+     314             :      * \param stamp  Time stamp of the measurement vector and covariance matrix.
+     315             :      * \param model  Optional pointer to a specific Model to be used with this measurement (eg. mapping it from different states). If it equals to nullptr, the
+     316             :      * default model specified in the constructor will be used.
+     317             :      *
+     318             :      * \note This is the variant of the method when reprediction is disabled and will function like a dumb LKF.
+     319             :      *
+     320             :      */
+     321             :     template<bool check=disable_reprediction>
+     322         292 :     std::enable_if_t<check> addMeasurement(const z_t& z, const R_t& R, const ros::Time& stamp, const ModelPtr& model = nullptr, const double& meas_id = -1)
+     323             :     {
+     324         292 :       if (m_history.empty())
+     325           0 :         m_history.push_back({stamp});
+     326         292 :       auto& info = m_history.front();
+     327         292 :       const ros::Time to_stamp = stamp > info.stamp ? stamp : info.stamp;
+     328         292 :       const auto sc = predictTo(to_stamp);
+     329         292 :       info.z = z;
+     330         292 :       info.R = R;
+     331         292 :       info.stamp = to_stamp;
+     332         292 :       info.is_measurement = true;
+     333         292 :       info.meas_id = meas_id;
+     334         292 :       info.correct_model = model;
+     335         292 :       m_sc = correctFrom(sc, info);
+     336         292 :     }
+     337             :     //}
+     338             : 
+     339             :   public:
+     340             :     /* constructor //{ */
+     341             : 
+     342             :     /*!
+     343             :      * \brief The main constructor.
+     344             :      *
+     345             :      * Initializes the Repredictor with the necessary initial and default values.
+     346             :      *
+     347             :      * \param x0             Initial state.
+     348             :      * \param P0             Covariance matrix of the initial state uncertainty.
+     349             :      * \param u0             Initial system input.
+     350             :      * \param Q0             Default covariance matrix of the process noise.
+     351             :      * \param t0             Time stamp of the initial state.
+     352             :      * \param model          Default prediction and correction model.
+     353             :      * \param hist_len       Length of the history buffer for system inputs and measurements.
+     354             :      */
+     355           3 :     Repredictor(const x_t& x0, const P_t& P0, const u_t& u0, const Q_t& Q0, const ros::Time& t0, const ModelPtr& model, const unsigned hist_len)
+     356           3 :         : m_sc{x0, P0}, m_default_model(model), m_history(history_t(hist_len))
+     357             :     {
+     358           3 :       assert(hist_len > 0);
+     359           3 :       addInputChangeWithNoise(u0, Q0, t0, model);
+     360           3 :     };
+     361             : 
+     362             :     /*!
+     363             :      * \brief Empty constructor.
+     364             :      *
+     365             :      */
+     366             :     Repredictor(){};
+     367             : 
+     368             :     /*!
+     369             :      * \brief Variation of the constructor for cases without a system input.
+     370             :      *
+     371             :      * Initializes the Repredictor with the necessary initial and default values.
+     372             :      * Assumes the system input is zero at t0.
+     373             :      *
+     374             :      * \param x0             Initial state.
+     375             :      * \param P0             Covariance matrix of the initial state uncertainty.
+     376             :      * \param Q0             Default covariance matrix of the process noise.
+     377             :      * \param t0             Time stamp of the initial state.
+     378             :      * \param model          Default prediction and correction model.
+     379             :      * \param hist_len       Length of the history buffer for system inputs and measurements.
+     380             :      */
+     381             :     Repredictor(const x_t& x0, const P_t& P0, const Q_t& Q0, const ros::Time& t0, const ModelPtr& model, const unsigned hist_len)
+     382             :         : m_sc{x0, P0}, m_default_model(model), m_history(history_t(hist_len))
+     383             :     {
+     384             :       assert(hist_len > 0);
+     385             :       const u_t u0{0};
+     386             :       addInputChangeWithNoise(u0, Q0, t0, model);
+     387             :     };
+     388             :     //}
+     389             : 
+     390             :   protected:
+     391             :     // state and covariance corresponding to the oldest element in the history buffer
+     392             :     statecov_t m_sc;
+     393             :     // default model to use for updates
+     394             :     ModelPtr m_default_model;
+     395             : 
+     396             :   private:
+     397             :     /* helper structs and usings //{ */
+     398             : 
+     399             :     struct info_t
+     400             :     {
+     401             :       ros::Time stamp;
+     402             : 
+     403             :       // system input-related information
+     404             :       u_t u;
+     405             :       Q_t Q;
+     406             :       ModelPtr predict_model;
+     407             : 
+     408             :       // measurement-related information (unused in case is_measurement=false)
+     409             :       z_t z;
+     410             :       R_t R;
+     411             :       ModelPtr correct_model;
+     412             :       bool is_measurement;
+     413             :       int meas_id;
+     414             : 
+     415             :       // constructor for a dummy info (for searching in the history)
+     416         638 :       info_t(const ros::Time& stamp) : stamp(stamp), is_measurement(false){};
+     417             : 
+     418             :       // constructor for a system input
+     419         200 :       info_t(const ros::Time& stamp, const u_t& u, const Q_t& Q, const ModelPtr& model)
+     420         200 :           : stamp(stamp), u(u), Q(Q), predict_model(model), is_measurement(false){};
+     421             : 
+     422             :       // constructor for a measurement
+     423         100 :       info_t(const ros::Time& stamp, const z_t& z, const R_t& R, const ModelPtr& model, const info_t& prev_info, const int& meas_id)
+     424         100 :           : stamp(stamp), z(z), R(R), correct_model(model), is_measurement(true), meas_id(meas_id)
+     425             :       {
+     426         100 :         updateUsing(prev_info);
+     427         100 :       };
+     428             : 
+     429             :       // copy system input-related information from a previous info
+     430        5639 :       void updateUsing(const info_t& info)
+     431             :       {
+     432        5639 :         u = info.u;
+     433        5639 :         Q = info.Q;
+     434        5639 :         predict_model = info.predict_model;
+     435        5639 :       };
+     436             :     };
+     437             : 
+     438             : 
+     439             :     //}
+     440             : 
+     441             :   protected:
+     442             :     using history_t = boost::circular_buffer<info_t>;
+     443             :     // the history buffer
+     444             :     history_t m_history;
+     445             : 
+     446             :     // | ---------------- helper debugging methods ---------------- |
+     447             :     /* checkMonotonicity() method //{ */
+     448             :     template <typename T>
+     449             :     bool checkMonotonicity(const T& buf)
+     450             :     {
+     451             :       if (buf.empty())
+     452             :         return true;
+     453             :       for (auto it = std::begin(buf) + 1; it != std::end(buf); it++)
+     454             :         if (earlier(*it, *(it - 1)))
+     455             :           return false;
+     456             :       return true;
+     457             :     }
+     458             :     //}
+     459             : 
+     460             :     /* printBuffer() method //{ */
+     461             :     template <typename T>
+     462             :     void printBuffer(const T& buf)
+     463             :     {
+     464             :       if (buf.empty())
+     465             :         return;
+     466             :       const auto first_stamp = buf.front().stamp;
+     467             :       std::cerr << "first stamp: " << first_stamp << std::endl;
+     468             :       for (size_t it = 0; it < buf.size(); it++)
+     469             :       {
+     470             :         std::cerr << it << ":\t" << buf.at(it).stamp - first_stamp << std::endl;
+     471             :       }
+     472             :     }
+     473             :     //}
+     474             : 
+     475             :   private:
+     476             :     // | -------------- helper implementation methods ------------- |
+     477             : 
+     478             :     /* addInfo() method //{ */
+     479         300 :     typename history_t::iterator addInfo(const info_t& info, const typename history_t::iterator& next_it)
+     480             :     {
+     481             :       // check if the new element would be added before the first element of the history buffer and ignore it if so
+     482         300 :       if (next_it == std::begin(m_history) && !m_history.empty())
+     483             :       {
+     484           0 :         ROS_WARN_STREAM_THROTTLE(1.0, "[Repredictor]: Added history point is older than the oldest by "
+     485             :                                           << (next_it->stamp - info.stamp).toSec()
+     486             :                                           << "s. Ignoring it! Consider increasing the history buffer size (currently: " << m_history.size() << ")");
+     487           0 :         return std::end(m_history);
+     488             :       }
+     489             : 
+     490             :       // check if adding a new element would throw out the oldest one
+     491         300 :       if (m_history.size() == m_history.capacity())
+     492             :       {  // if so, first update m_sc
+     493             :         // figure out, what will be the oldest element in the buffer after inserting the newly received one
+     494           0 :         auto new_oldest = m_history.front();
+     495           0 :         if (m_history.size() == 1 || (m_history.size() > 1 && info.stamp > m_history.at(0).stamp && info.stamp < m_history.at(1).stamp))
+     496             :         {
+     497           0 :           new_oldest = info;
+     498           0 :         } else if (m_history.size() > 1)
+     499             :         {
+     500           0 :           new_oldest = m_history.at(1);
+     501             :         }
+     502             :         // update m_sc to the time of the new oldest element (after inserting the new element)
+     503           0 :         m_sc = predictTo(new_oldest.stamp);
+     504             :         // insert the new element into the history buffer, causing the original oldest element to be removed
+     505             :       }
+     506             : 
+     507             :       // add the new point finally
+     508         300 :       const auto ret = m_history.insert(next_it, info);
+     509             :       /* debug check //{ */
+     510             : 
+     511             : #ifdef REPREDICTOR_DEBUG
+     512             :       if (!checkMonotonicity(m_history))
+     513             :       {
+     514             :         std::cerr << "History buffer is not monotonous after modification!" << std::endl;
+     515             :       }
+     516             :       std::cerr << "Added info (" << m_history.size() << " total)" << std::endl;
+     517             : #endif
+     518             : 
+     519             :       //}
+     520         300 :       return ret;
+     521             :     }
+     522             :     //}
+     523             : 
+     524             :     /* earlier() method //{ */
+     525        2047 :     static bool earlier(const info_t& ob1, const info_t& ob2)
+     526             :     {
+     527        2047 :       return ob1.stamp < ob2.stamp;
+     528             :     }
+     529             :     //}
+     530             : 
+     531             :     /* predictFrom() method //{ */
+     532       16039 :     statecov_t predictFrom(const statecov_t& sc, const info_t& inpt, const ros::Time& from_stamp, const ros::Time& to_stamp)
+     533             :     {
+     534       32078 :       const auto model = inpt.predict_model == nullptr ? m_default_model : inpt.predict_model;
+     535       16039 :       const auto dt = (to_stamp - from_stamp).toSec();
+     536       32078 :       return model->predict(sc, inpt.u, inpt.Q, dt);
+     537             :     }
+     538             :     //}
+     539             : 
+     540             :     /* correctFrom() method //{ */
+     541        5442 :     statecov_t correctFrom(const statecov_t& sc, const info_t& meas)
+     542             :     {
+     543        5442 :       assert(meas.is_measurement);
+     544       10884 :       const auto model = meas.correct_model == nullptr ? m_default_model : meas.correct_model;
+     545        5442 :       auto sc_tmp = sc;
+     546       10884 :       return model->correct(sc_tmp, meas.z, meas.R);
+     547             :     }
+     548             :     //}
+     549             :   };
+     550             : }  // namespace mrs_lib
+     551             : 
+     552             : 
+     553             : #endif  // REPREDICTOR_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/service_client_handler.h.func-sort-c.html b/mrs_lib/include/mrs_lib/service_client_handler.h.func-sort-c.html new file mode 100644 index 0000000000..6a05760a7b --- /dev/null +++ b/mrs_lib/include/mrs_lib/service_client_handler.h.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/service_client_handler.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - service_client_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:33100.0 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEEC2Ev2
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEED2Ev2
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEED2Ev4
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/service_client_handler.h.func.html b/mrs_lib/include/mrs_lib/service_client_handler.h.func.html new file mode 100644 index 0000000000..1f09d63c11 --- /dev/null +++ b/mrs_lib/include/mrs_lib/service_client_handler.h.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/service_client_handler.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - service_client_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:33100.0 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEEC2Ev2
_ZN7mrs_lib20ServiceClientHandlerIN8std_srvs7TriggerEED2Ev4
_ZN7mrs_lib25ServiceClientHandler_implIN8std_srvs7TriggerEED2Ev2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/service_client_handler.h.gcov.html b/mrs_lib/include/mrs_lib/service_client_handler.h.gcov.html new file mode 100644 index 0000000000..61746ab360 --- /dev/null +++ b/mrs_lib/include/mrs_lib/service_client_handler.h.gcov.html @@ -0,0 +1,319 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/service_client_handler.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - service_client_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:33100.0 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /**  \file
+       2             :      \brief Defines ServiceClientHandler and related convenience classes for upgrading the ROS service client
+       3             :      \author Tomas Baca - tomas.baca@fel.cvut.cz
+       4             :  */
+       5             : #ifndef SERVICE_CLIENT_HANDLER_H
+       6             : #define SERVICE_CLIENT_HANDLER_H
+       7             : 
+       8             : #include <ros/ros.h>
+       9             : #include <ros/package.h>
+      10             : 
+      11             : #include <string>
+      12             : #include <future>
+      13             : #include <mutex>
+      14             : 
+      15             : namespace mrs_lib
+      16             : {
+      17             : 
+      18             : /* class ServiceClientHandler_impl //{ */
+      19             : 
+      20             : /**
+      21             :  * @brief implementation of the service client handler
+      22             :  */
+      23             : template <class ServiceType>
+      24             : class ServiceClientHandler_impl {
+      25             : 
+      26             : public:
+      27             :   /**
+      28             :    * @brief default constructor
+      29             :    */
+      30             :   ServiceClientHandler_impl(void);
+      31             : 
+      32             :   /**
+      33             :    * @brief default destructor
+      34             :    */
+      35           2 :   ~ServiceClientHandler_impl(void){};
+      36             : 
+      37             :   /**
+      38             :    * @brief constructor
+      39             :    *
+      40             :    * @param nh ROS node handler
+      41             :    * @param address service address
+      42             :    */
+      43             :   ServiceClientHandler_impl(ros::NodeHandle& nh, const std::string& address);
+      44             : 
+      45             :   /**
+      46             :    * @brief "classic" synchronous service call
+      47             :    *
+      48             :    * @param srv data
+      49             :    *
+      50             :    * @return true when success
+      51             :    */
+      52             :   bool call(ServiceType& srv);
+      53             : 
+      54             :   /**
+      55             :    * @brief "classic" synchronous service call with repeats after an error
+      56             :    *
+      57             :    * @param srv data
+      58             :    * @param attempts how many attempts for the call
+      59             :    *
+      60             :    * @return  true when success
+      61             :    */
+      62             :   bool call(ServiceType& srv, const int& attempts);
+      63             : 
+      64             :   /**
+      65             :    * @brief "classic" synchronous service call with repeats after an error
+      66             :    *
+      67             :    * @param srv data
+      68             :    * @param attempts how many attempts for the call
+      69             :    * @param repeat_delay how long to wait before repeating the call
+      70             :    *
+      71             :    * @return  true when success
+      72             :    */
+      73             :   bool call(ServiceType& srv, const int& attempts, const double& repeat_delay);
+      74             : 
+      75             :   /**
+      76             :    * @brief asynchronous service call
+      77             :    *
+      78             :    * @param srv data
+      79             :    *
+      80             :    * @return future result
+      81             :    */
+      82             :   std::future<ServiceType> callAsync(ServiceType& srv);
+      83             : 
+      84             :   /**
+      85             :    * @brief asynchronous service call with repeates after an error
+      86             :    *
+      87             :    * @param srv data
+      88             :    * @param attempts how many attempts for the call
+      89             :    *
+      90             :    * @return future result
+      91             :    */
+      92             :   std::future<ServiceType> callAsync(ServiceType& srv, const int& attempts);
+      93             : 
+      94             :   /**
+      95             :    * @brief asynchronous service call with repeates after an error
+      96             :    *
+      97             :    * @param srv data
+      98             :    * @param attempts how many attempts for the call
+      99             :    * @param repeat_delay how long to wait before repeating the call
+     100             :    *
+     101             :    * @return future result
+     102             :    */
+     103             :   std::future<ServiceType> callAsync(ServiceType& srv, const int& attempts, const double& repeat_delay);
+     104             : 
+     105             : private:
+     106             :   ros::ServiceClient service_client_;
+     107             :   std::mutex         mutex_service_client_;
+     108             :   std::atomic<bool>  service_initialized_;
+     109             : 
+     110             :   std::string _address_;
+     111             : 
+     112             :   ServiceType async_data_;
+     113             :   int         async_attempts_;
+     114             :   double      async_repeat_delay_;
+     115             :   std::mutex  mutex_async_;
+     116             : 
+     117             :   ServiceType asyncRun(void);
+     118             : };
+     119             : 
+     120             : //}
+     121             : 
+     122             : /* class ServiceClientHandler //{ */
+     123             : 
+     124             : /**
+     125             :  * @brief user wrapper of the service client handler implementation
+     126             :  */
+     127             : template <class ServiceType>
+     128             : class ServiceClientHandler {
+     129             : 
+     130             : public:
+     131             :   /**
+     132             :    * @brief generic constructor
+     133             :    */
+     134           2 :   ServiceClientHandler(void){};
+     135             : 
+     136             :   /**
+     137             :    * @brief generic destructor
+     138             :    */
+     139           4 :   ~ServiceClientHandler(void){};
+     140             : 
+     141             :   /**
+     142             :    * @brief operator=
+     143             :    *
+     144             :    * @param other
+     145             :    *
+     146             :    * @return
+     147             :    */
+     148             :   ServiceClientHandler& operator=(const ServiceClientHandler& other);
+     149             : 
+     150             :   /**
+     151             :    * @brief copy constructor
+     152             :    *
+     153             :    * @param other
+     154             :    */
+     155             :   ServiceClientHandler(const ServiceClientHandler& other);
+     156             : 
+     157             :   /**
+     158             :    * @brief constructor
+     159             :    *
+     160             :    * @param nh ROS node handler
+     161             :    * @param address service address
+     162             :    */
+     163             :   ServiceClientHandler(ros::NodeHandle& nh, const std::string& address);
+     164             : 
+     165             :   /**
+     166             :    * @brief initializer
+     167             :    *
+     168             :    * @param nh ROS node handler
+     169             :    * @param address service address
+     170             :    */
+     171             :   void initialize(ros::NodeHandle& nh, const std::string& address);
+     172             : 
+     173             :   /**
+     174             :    * @brief "standard" synchronous call
+     175             :    *
+     176             :    * @param srv data
+     177             :    *
+     178             :    * @return true when success
+     179             :    */
+     180             :   bool call(ServiceType& srv);
+     181             : 
+     182             :   /**
+     183             :    * @brief "standard" synchronous call with repeats after failure
+     184             :    *
+     185             :    * @param srv data
+     186             :    * @param attempts how many attempts for the call
+     187             :    *
+     188             :    * @return true when success
+     189             :    */
+     190             :   bool call(ServiceType& srv, const int& attempts);
+     191             : 
+     192             :   /**
+     193             :    * @brief "standard" synchronous call with repeats after failure
+     194             :    *
+     195             :    * @param srv data
+     196             :    * @param attempts how many attempts for the call
+     197             :    * @param repeat_delay how long to wait before repeating the call
+     198             :    *
+     199             :    * @return true when success
+     200             :    */
+     201             :   bool call(ServiceType& srv, const int& attempts, const double& repeat_delay);
+     202             : 
+     203             :   /**
+     204             :    * @brief asynchronous call
+     205             :    *
+     206             :    * @param srv data
+     207             :    *
+     208             :    * @return future result
+     209             :    */
+     210             :   std::future<ServiceType> callAsync(ServiceType& srv);
+     211             : 
+     212             :   /**
+     213             :    * @brief asynchronous call with repeats after failure
+     214             :    *
+     215             :    * @param srv data
+     216             :    * @param attempts how many attemps for the call
+     217             :    *
+     218             :    * @return future result
+     219             :    */
+     220             :   std::future<ServiceType> callAsync(ServiceType& srv, const int& attempts);
+     221             : 
+     222             :   /**
+     223             :    * @brief asynchronous call with repeats after failure
+     224             :    *
+     225             :    * @param srv data
+     226             :    * @param attempts how many attemps for the call
+     227             :    * @param repeat_delay how long to wait before repeating the call
+     228             :    *
+     229             :    * @return future result
+     230             :    */
+     231             :   std::future<ServiceType> callAsync(ServiceType& srv, const int& attempts, const double& repeat_delay);
+     232             : 
+     233             : private:
+     234             :   std::shared_ptr<ServiceClientHandler_impl<ServiceType>> impl_;
+     235             : };
+     236             : 
+     237             : //}
+     238             : 
+     239             : }  // namespace mrs_lib
+     240             : 
+     241             : #include <mrs_lib/impl/service_client_handler.hpp>
+     242             : 
+     243             : #endif  // SERVICE_CLIENT_HANDLER_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/subscribe_handler.h.func-sort-c.html b/mrs_lib/include/mrs_lib/subscribe_handler.h.func-sort-c.html new file mode 100644 index 0000000000..9b83f6e0aa --- /dev/null +++ b/mrs_lib/include/mrs_lib/subscribe_handler.h.func-sort-c.html @@ -0,0 +1,152 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/subscribe_handler.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - subscribe_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:314077.5 %
Date:2023-11-29 14:09:54Functions:132065.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE10waitForNewERKN3ros12WallDurationE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE6getMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE19subscribedTopicNameB5cxx11Ev0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE6newMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE7peekMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE7usedMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE9topicNameB5cxx11Ev0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2ERKNS_23SubscribeHandlerOptionsERKSt8functionIFvN5boost10shared_ptrIKS4_EEEE1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2Ev1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2IJPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsERKSt8functionIFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEEDpT_1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2IJPFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsESE_DpT_1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEaSEOS5_1
_ZN7mrs_lib23SubscribeHandlerOptionsC2Ev1
_ZZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC4IJPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsERKSt8functionIFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEEDpT_ENKUlvE_clEv1
_ZZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC4IJPFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsESE_DpT_ENKUlvE_clEv1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEED2Ev2
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4stopEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE5startEv5
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE11lastMsgTimeEv5
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE6hasMsgEv10000
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/subscribe_handler.h.func.html b/mrs_lib/include/mrs_lib/subscribe_handler.h.func.html new file mode 100644 index 0000000000..90f5868c23 --- /dev/null +++ b/mrs_lib/include/mrs_lib/subscribe_handler.h.func.html @@ -0,0 +1,152 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/subscribe_handler.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - subscribe_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:314077.5 %
Date:2023-11-29 14:09:54Functions:132065.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE10waitForNewERKN3ros12WallDurationE0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE4stopEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE5startEv5
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE6getMsgEv0
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2ERKNS_23SubscribeHandlerOptionsERKSt8functionIFvN5boost10shared_ptrIKS4_EEEE1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2Ev1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2IJPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsERKSt8functionIFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEEDpT_1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC2IJPFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsESE_DpT_1
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEED2Ev2
_ZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEaSEOS5_1
_ZN7mrs_lib23SubscribeHandlerOptionsC2Ev1
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE11lastMsgTimeEv5
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE19subscribedTopicNameB5cxx11Ev0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE6hasMsgEv10000
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE6newMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE7peekMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE7usedMsgEv0
_ZNK7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEE9topicNameB5cxx11Ev0
_ZZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC4IJPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsERKSt8functionIFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEEDpT_ENKUlvE_clEv1
_ZZN7mrs_lib16SubscribeHandlerIN13geometry_msgs13PointStamped_ISaIvEEEEC4IJPFvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeEEPFvN5boost10shared_ptrIKS4_EEEEEERKNS_23SubscribeHandlerOptionsESE_DpT_ENKUlvE_clEv1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/subscribe_handler.h.gcov.html b/mrs_lib/include/mrs_lib/subscribe_handler.h.gcov.html new file mode 100644 index 0000000000..d6320d8cb1 --- /dev/null +++ b/mrs_lib/include/mrs_lib/subscribe_handler.h.gcov.html @@ -0,0 +1,540 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/subscribe_handler.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - subscribe_handler.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:314077.5 %
Date:2023-11-29 14:09:54Functions:132065.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : /**  \file
+       3             :      \brief Defines SubscribeHandler and related convenience classes for subscribing to ROS topics.
+       4             :      \author Matouš Vrba - vrbamato@fel.cvut.cz
+       5             :  */
+       6             : 
+       7             : #ifndef SUBRSCRIBE_HANDLER_H
+       8             : #define SUBRSCRIBE_HANDLER_H
+       9             : 
+      10             : #include <ros/ros.h>
+      11             : #include <mrs_lib/timeout_manager.h>
+      12             : 
+      13             : namespace mrs_lib
+      14             : {
+      15             : 
+      16             :   static const ros::Duration no_timeout = ros::Duration(0);
+      17             : 
+      18             :   /* struct SubscribeHandlerOptions //{ */
+      19             :   
+      20             :   /**
+      21             :   * \brief A helper class to simplify setup of SubscribeHandler construction.
+      22             :   * This class is passed to the SubscribeHandler constructor and specifies its common options.
+      23             :   *
+      24             :   * \note Any option, passed directly to the SubscribeHandler constructor outside this structure, *OVERRIDES* values in this structure.
+      25             :   * The values in this structure can be thought of as default common values for all SubscribeHandler objects you want to create,
+      26             :   * and values passed directly to the constructor as specific options for the concrete handler.
+      27             :   *
+      28             :   */
+      29             :   struct SubscribeHandlerOptions
+      30             :   {
+      31             :     SubscribeHandlerOptions(const ros::NodeHandle& nh) : nh(nh) {}
+      32           1 :     SubscribeHandlerOptions() = default;
+      33             :   
+      34             :     ros::NodeHandle nh;  /*!< \brief The ROS NodeHandle to be used for subscription. */
+      35             :   
+      36             :     std::string node_name = {};  /*!< \brief Name of the ROS node, using this handle (used for messages printed to console). */
+      37             :   
+      38             :     std::string topic_name = {};  /*!< \brief Name of the ROS topic to be handled. */
+      39             : 
+      40             :     std::shared_ptr<mrs_lib::TimeoutManager> timeout_manager = nullptr;  /*!< \brief Will be used for handling message timouts if necessary. If no manager is specified, it will be created with rate equal to half of \p no_message_timeout. */
+      41             :   
+      42             :     ros::Duration no_message_timeout = mrs_lib::no_timeout;  /*!< \brief If no new message is received for this duration, the \p timeout_callback function will be called. If \p timeout_callback is empty, an error message will be printed to the console. */
+      43             :   
+      44             :     std::function<void(const std::string& topic_name, const ros::Time& last_msg)> timeout_callback = {};  /*!< \brief This function will be called if no new message is received for the \p no_message_timeout duration. If this variable is empty, an error message will be printed to the console. */
+      45             :   
+      46             :     bool threadsafe = true;  /*!< \brief If true, all methods of the SubscribeHandler will be mutexed (using a recursive mutex) to avoid data races. */
+      47             :   
+      48             :     bool autostart = true;  /*!< \brief If true, the SubscribeHandler will be started after construction. Otherwise it has to be started using the start() method */
+      49             :   
+      50             :     uint32_t queue_size = 3;  /*!< \brief This parameter is passed to the NodeHandle when subscribing to the topic */
+      51             :   
+      52             :     ros::TransportHints transport_hints = ros::TransportHints();  /*!< \brief This parameter is passed to the NodeHandle when subscribing to the topic */
+      53             :   };
+      54             :   
+      55             :   //}
+      56             : 
+      57             :   /* SubscribeHandler class //{ */
+      58             :   /**
+      59             :   * \brief The main class for ROS topic subscription, message timeout handling etc.
+      60             :   *
+      61             :   * This class handles the raw ROS Subscriber for a specified topic. The last message received on the topic is remembered
+      62             :   * and may be retrieved by calling the getMsg() method. To check whether at least one message was received, use hasMsg()
+      63             :   * (if no message was received and you call getMsg(), a nullptr is returned and an error message is printed). To check
+      64             :   * whether a new message has arrived since the last call to getMsg(), use newMsg() (useful to check whether a new message
+      65             :   * needs to be processed in a loop or ROS Timer callback).
+      66             :   *
+      67             :   * A timeout callback function may be specified, which is called if no message is received on the topic for a specified
+      68             :   * timeout (use the \p timeout_callback and \p no_message_timeout parameters). If the timeout callback is not set by the
+      69             :   * user, an error message is printed to the console after the timeout by default.
+      70             :   *
+      71             :   * A message callback function may be specified, which is called whenever a new message is received (use the
+      72             :   * \p message_callback parameter).
+      73             :   *
+      74             :   * The callbacks and timeouts may be stopped and started using the stop() and start() methods.
+      75             :   *
+      76             :   * For more details, see the example below (I recommend starting with the simple_example which covers most use-cases).
+      77             :   *
+      78             :   */
+      79             :   template <typename MessageType>
+      80             :   class SubscribeHandler
+      81             :   {
+      82             :     public:
+      83             :     /*!
+      84             :       * \brief Convenience type for the template parameter to enable nice aliasing.
+      85             :       */
+      86             :       using message_type = MessageType;
+      87             : 
+      88             :     /*!
+      89             :       * \brief Type for the timeout callback function.
+      90             :       */
+      91             :       using timeout_callback_t = std::function<void(const std::string& topic_name, const ros::Time& last_msg)>;
+      92             : 
+      93             :     /*!
+      94             :       * \brief Convenience type for the message callback function.
+      95             :       */
+      96             :       using message_callback_t = std::function<void(typename MessageType::ConstPtr)>;
+      97             : 
+      98             :     public:
+      99             :     /*!
+     100             :       * \brief Returns the last received message on the topic, handled by this SubscribeHandler.
+     101             :       * Use hasMsg() first to check if at least one message is available or newMsg() to check if a new message
+     102             :       * since the last call to getMsg() is available.
+     103             :       *
+     104             :       * \return the last received message.
+     105             :       */
+     106           0 :       virtual typename MessageType::ConstPtr getMsg() {assert(m_pimpl); return m_pimpl->getMsg();};
+     107             : 
+     108             :     /*!
+     109             :       * \brief Returns the last received message on the topic without modifying the newMsg() or usedMsg() flags.
+     110             :       *
+     111             :       * \return the last received message.
+     112             :       */
+     113           0 :       virtual typename MessageType::ConstPtr peekMsg() const {assert(m_pimpl); return m_pimpl->peekMsg();};
+     114             : 
+     115             :     /*!
+     116             :       * \brief Used to check whether at least one message has been received on the handled topic.
+     117             :       *
+     118             :       * \return true if at least one message was received, otherwise false.
+     119             :       */
+     120       10000 :       virtual bool hasMsg() const {assert(m_pimpl); return m_pimpl->hasMsg();};
+     121             : 
+     122             :     /*!
+     123             :       * \brief Used to check whether at least one message has been received on the handled topic since the last call to getMsg().
+     124             :       *
+     125             :       * \return true if at least one message was received, otherwise false.
+     126             :       */
+     127           0 :       virtual bool newMsg() const {assert(m_pimpl); return m_pimpl->newMsg();};
+     128             : 
+     129             :     /*!
+     130             :       * \brief Used to check whether getMsg() was called at least once on this SubscribeHandler.
+     131             :       *
+     132             :       * \return true if getMsg() was called at least once, otherwise false.
+     133             :       */
+     134           0 :       virtual bool usedMsg() const {assert(m_pimpl); return m_pimpl->usedMsg();};
+     135             : 
+     136             :     /*!
+     137             :       * \brief Blocks until new data becomes available or until the timeout runs out or until a spurious wake-up.
+     138             :       *
+     139             :       * \return the message if a new message is available after waking up, \p nullptr otherwise.
+     140             :       */
+     141           0 :       virtual typename MessageType::ConstPtr waitForNew(const ros::WallDuration& timeout) {assert(m_pimpl); return m_pimpl->waitForNew(timeout);};
+     142             : 
+     143             :     /*!
+     144             :       * \brief Returns time of the last received message on the topic, handled by this SubscribeHandler.
+     145             :       *
+     146             :       * \return time when the last message was received.
+     147             :       */
+     148           5 :       virtual ros::Time lastMsgTime() const {assert(m_pimpl); return m_pimpl->lastMsgTime();};
+     149             : 
+     150             :     /*!
+     151             :       * \brief Returns the resolved (full) name of the topic, handled by this SubscribeHandler.
+     152             :       *
+     153             :       * \return name of the handled topic.
+     154             :       */
+     155           0 :       virtual std::string topicName() const {assert(m_pimpl); return m_pimpl->topicName();};
+     156             : 
+     157             :     /*!
+     158             :       * \brief Returns the subscribed (unresolved) name of the topic, handled by this SubscribeHandler.
+     159             :       *
+     160             :       * \return name of the handled topic.
+     161             :       */
+     162           0 :       virtual std::string subscribedTopicName() const {assert(m_pimpl); return m_pimpl->m_topic_name;};
+     163             : 
+     164             :     /*!
+     165             :       * \brief Enables the callbacks for the handled topic.
+     166             :       *
+     167             :       * If the SubscribeHandler object is stopped using the stop() method, no callbacks will be called
+     168             :       * until the start() method is called.
+     169             :       */
+     170           5 :       virtual void start() {assert(m_pimpl); return m_pimpl->start();};
+     171             : 
+     172             :     /*!
+     173             :       * \brief Disables the callbacks for the handled topic.
+     174             :       *
+     175             :       * All messages after this method is called will be ignored until start() is called again.
+     176             :       * Timeout checking will also be disabled.
+     177             :       */
+     178           5 :       virtual void stop() {assert(m_pimpl); return m_pimpl->stop();};
+     179             : 
+     180             :     public:
+     181             :     /*!
+     182             :       * \brief Default constructor to avoid having to use pointers.
+     183             :       *
+     184             :       * It does nothing and the SubscribeHandler it constructs will also do nothing.
+     185             :       * Use some of the other constructors for actual construction of a usable SubscribeHandler.
+     186             :       */
+     187           1 :       SubscribeHandler() {};
+     188             : 
+     189             :     /*!
+     190             :       * \brief Main constructor.
+     191             :       *
+     192             :       * \param options    The common options struct (see documentation of SubscribeHandlerOptions).
+     193             :       * \param topic_name Name of the topic to be handled by this subscribed.
+     194             :       * \param args       Remaining arguments to be parsed (see other constructors).
+     195             :       *
+     196             :       */
+     197             :       template<class ... Types>
+     198           1 :       SubscribeHandler(
+     199             :             const SubscribeHandlerOptions& options,
+     200             :             const std::string& topic_name,
+     201             :             Types ... args
+     202             :           )
+     203             :       :
+     204             :         SubscribeHandler(
+     205           1 :             [options, topic_name]()
+     206             :             {
+     207           2 :               SubscribeHandlerOptions opts = options;
+     208           1 :               opts.topic_name = topic_name;
+     209           2 :               return opts;
+     210             :             }(),
+     211             :             args...
+     212           1 :             )
+     213             :       {
+     214           1 :       }
+     215             : 
+     216             :     /*!
+     217             :       * \brief Convenience constructor overload.
+     218             :       *
+     219             :       * \param options          The common options struct (see documentation of SubscribeHandlerOptions).
+     220             :       * \param message_callback The callback function to call when a new message is received (you can leave this argument empty and just use the newMsg()/hasMsg() and getMsg() interface).
+     221             :       *
+     222             :       */
+     223           1 :       SubscribeHandler(
+     224             :             const SubscribeHandlerOptions& options,
+     225             :             const message_callback_t& message_callback = {}
+     226             :           )
+     227           1 :       {
+     228           1 :         if (options.threadsafe)
+     229             :         {
+     230           1 :           m_pimpl = std::make_unique<ImplThreadsafe>
+     231             :             (
+     232             :               options,
+     233             :               message_callback
+     234             :             );
+     235             :         }
+     236             :         else
+     237             :         {
+     238           0 :           m_pimpl = std::make_unique<Impl>
+     239             :             (
+     240             :               options,
+     241             :               message_callback
+     242             :             );
+     243             :         }
+     244           1 :         if (options.autostart)
+     245           0 :           start();
+     246           1 :       };
+     247             : 
+     248             :     /*!
+     249             :       * \brief Convenience constructor overload.
+     250             :       *
+     251             :       * \param options          The common options struct (see documentation of SubscribeHandlerOptions).
+     252             :       * \param timeout_callback The callback function to call when a new message is not received for the duration, specified in \p options or in the \p no_message_timeout parameter.
+     253             :       * \param args             Remaining arguments to be parsed (see other constructors).
+     254             :       *
+     255             :       */
+     256             :       template <class ... Types>
+     257           1 :       SubscribeHandler(
+     258             :             const SubscribeHandlerOptions& options,
+     259             :             const timeout_callback_t& timeout_callback,
+     260             :             Types ... args
+     261             :           )
+     262             :       :
+     263             :         SubscribeHandler(
+     264           1 :             [options, timeout_callback]()
+     265             :             {
+     266           2 :               SubscribeHandlerOptions opts = options;
+     267           1 :               opts.timeout_callback = timeout_callback;
+     268           2 :               return opts;
+     269             :             }(),
+     270             :             args...
+     271           1 :             )
+     272             :       {
+     273           1 :       }
+     274             : 
+     275             :     /*!
+     276             :       * \brief Convenience constructor overload.
+     277             :       *
+     278             :       * \param options          The common options struct (see documentation of SubscribeHandlerOptions).
+     279             :       * \param timeout_callback The callback method to call when a new message is not received for the duration, specified in \p options or in the \p no_message_timeout parameter.
+     280             :       * \param obj1             The object on which the callback method \p timeout_callback will be called.
+     281             :       * \param args             Remaining arguments to be parsed (see other constructors).
+     282             :       *
+     283             :       */
+     284             :       template <class ObjectType1, class ... Types>
+     285             :       SubscribeHandler(
+     286             :             const SubscribeHandlerOptions& options,
+     287             :             void (ObjectType1::*const timeout_callback) (const std::string& topic_name, const ros::Time& last_msg),
+     288             :             ObjectType1* const obj1,
+     289             :             Types ... args
+     290             :           )
+     291             :       :
+     292             :         SubscribeHandler(
+     293             :             [options, timeout_callback, obj1]()
+     294             :             {
+     295             :               SubscribeHandlerOptions opts = options;
+     296             :               opts.timeout_callback = timeout_callback == nullptr ? timeout_callback_t() : std::bind(timeout_callback, obj1, std::placeholders::_1, std::placeholders::_2);
+     297             :               return opts;
+     298             :             }(),
+     299             :             args...
+     300             :             )
+     301             :       {
+     302             :       }
+     303             : 
+     304             :     /*!
+     305             :       * \brief Convenience constructor overload.
+     306             :       *
+     307             :       * \param options          The common options struct (see documentation of SubscribeHandlerOptions).
+     308             :       * \param message_callback The callback method to call when a new message is received.
+     309             :       * \param obj2             The object on which the callback method \p timeout_callback will be called.
+     310             :       * \param args             Remaining arguments to be parsed (see other constructors).
+     311             :       *
+     312             :       */
+     313             :       template <class ObjectType2, class ... Types>
+     314             :       SubscribeHandler(
+     315             :             const SubscribeHandlerOptions& options,
+     316             :             void (ObjectType2::*const message_callback) (typename MessageType::ConstPtr),
+     317             :             ObjectType2* const obj2,
+     318             :             Types ... args
+     319             :           )
+     320             :       :
+     321             :         SubscribeHandler(
+     322             :             options,
+     323             :             message_callback == nullptr ? message_callback_t() : std::bind(message_callback, obj2, std::placeholders::_1),
+     324             :             args...
+     325             :             )
+     326             :       {
+     327             :       }
+     328             : 
+     329             :     /*!
+     330             :       * \brief Convenience constructor overload.
+     331             :       *
+     332             :       * \param options          The common options struct (see documentation of SubscribeHandlerOptions).
+     333             :       * \param message_callback The callback method to call when a new message is received.
+     334             :       * \param obj2             The object on which the callback method \p timeout_callback will be called.
+     335             :       * \param timeout_callback The callback method to call when a new message is not received for the duration, specified in \p options or in the \p no_message_timeout parameter.
+     336             :       * \param obj1             The object on which the callback method \p timeout_callback will be called.
+     337             :       * \param args             Remaining arguments to be parsed (see other constructors).
+     338             :       *
+     339             :       */
+     340             :      template <class ObjectType1, class ObjectType2, class ... Types>
+     341             :      SubscribeHandler(
+     342             :            const SubscribeHandlerOptions& options,
+     343             :            void (ObjectType2::*const message_callback) (typename MessageType::ConstPtr),
+     344             :            ObjectType2* const obj2,
+     345             :            void (ObjectType1::*const timeout_callback) (const std::string& topic_name, const ros::Time& last_msg),
+     346             :            ObjectType1* const obj1,
+     347             :            Types ... args
+     348             :          )
+     349             :      :
+     350             :        SubscribeHandler(
+     351             :             [options, timeout_callback, obj1]()
+     352             :             {
+     353             :               SubscribeHandlerOptions opts = options;
+     354             :               opts.timeout_callback = timeout_callback == nullptr ? timeout_callback_t() : std::bind(timeout_callback, obj1, std::placeholders::_1, std::placeholders::_2);
+     355             :               return opts;
+     356             :             }(),
+     357             :             message_callback == nullptr ? message_callback_t() : std::bind(message_callback, obj2, std::placeholders::_1),
+     358             :             args...
+     359             :             )
+     360             :      {
+     361             :      }
+     362             : 
+     363             :     /*!
+     364             :       * \brief Convenience constructor overload.
+     365             :       *
+     366             :       * \param options            The common options struct (see documentation of SubscribeHandlerOptions).
+     367             :       * \param no_message_timeout If no message is received for this duration, the timeout callback function is called. If no timeout callback is specified, an error message is printed to the console.
+     368             :       * \param args               Remaining arguments to be parsed (see other constructors).
+     369             :       *
+     370             :       */
+     371             :       template<class ... Types>
+     372             :       SubscribeHandler(
+     373             :             const SubscribeHandlerOptions& options,
+     374             :             const ros::Duration& no_message_timeout,
+     375             :             Types ... args
+     376             :           )
+     377             :       :
+     378             :         SubscribeHandler(
+     379             :             [options, no_message_timeout]()
+     380             :             {
+     381             :               SubscribeHandlerOptions opts = options;
+     382             :               opts.no_message_timeout = no_message_timeout;
+     383             :               return opts;
+     384             :             }(),
+     385             :             args...
+     386             :             )
+     387             :       {
+     388             :       }
+     389             : 
+     390             :     /*!
+     391             :       * \brief Convenience constructor overload.
+     392             :       *
+     393             :       * \param options          The common options struct (see documentation of SubscribeHandlerOptions).
+     394             :       * \param timeout_manager  The manager for timeout callbacks.
+     395             :       * \param args             Remaining arguments to be parsed (see other constructors).
+     396             :       *
+     397             :       */
+     398             :       template <class ... Types>
+     399             :       SubscribeHandler(
+     400             :             const SubscribeHandlerOptions& options,
+     401             :             mrs_lib::TimeoutManager& timeout_manager,
+     402             :             Types ... args
+     403             :           )
+     404             :       :
+     405             :         SubscribeHandler(
+     406             :             options,
+     407             :             timeout_manager = timeout_manager,
+     408             :             args...
+     409             :             )
+     410             :       {
+     411             :       }
+     412             : 
+     413           2 :       ~SubscribeHandler() = default;
+     414             :       // delete copy constructor and assignment operator (forbid copying shandlers)
+     415             :       SubscribeHandler(const SubscribeHandler&) = delete;
+     416             :       SubscribeHandler& operator=(const SubscribeHandler&) = delete;
+     417             :       // define only move constructor and assignemnt operator
+     418             :       SubscribeHandler(SubscribeHandler&& other)
+     419             :       {
+     420             :         this->m_pimpl = std::move(other.m_pimpl);
+     421             :         other.m_pimpl = nullptr;
+     422             :       }
+     423           1 :       SubscribeHandler& operator=(SubscribeHandler&& other)
+     424             :       {
+     425           1 :         this->m_pimpl = std::move(other.m_pimpl);
+     426           1 :         other.m_pimpl = nullptr;
+     427           1 :         return *this;
+     428             :       }
+     429             : 
+     430             :     private:
+     431             :       class Impl;
+     432             :       class ImplThreadsafe;
+     433             :       std::unique_ptr<Impl> m_pimpl;
+     434             :   };
+     435             :   //}
+     436             : 
+     437             : /*!
+     438             :   * \brief Helper alias for convenient extraction of handled message type from a SubscribeHandlerPtr.
+     439             :   */
+     440             :   template<typename SubscribeHandler>
+     441             :   using message_type = typename SubscribeHandler::message_type;
+     442             : 
+     443             : /*!
+     444             :   * \brief Helper function for object construstion e.g. in case of member objects.
+     445             :   * This function is useful to avoid specifying object template parameters twice - once in definition of the variable and second time during object construction.
+     446             :   * This function can deduce the template parameters from the type of the already defined object, because it returns the newly constructed object as a reference
+     447             :   * argument and not as a return type.
+     448             :   *
+     449             :   * \param object The object to be constructed.
+     450             :   * \param args   These arguments are passed to the object constructor.
+     451             :   */
+     452             :   template<typename Class, class ... Types>
+     453             :   void construct_object(
+     454             :         Class& object,
+     455             :         Types ... args
+     456             :       )
+     457             :   {
+     458             :     object = Class(args...);
+     459             :   }
+     460             : }
+     461             : 
+     462             : #include <mrs_lib/impl/subscribe_handler.hpp>
+     463             : 
+     464             : #endif // SUBRSCRIBE_HANDLER_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/timeout_manager.h.func-sort-c.html b/mrs_lib/include/mrs_lib/timeout_manager.h.func-sort-c.html new file mode 100644 index 0000000000..a49f5465d1 --- /dev/null +++ b/mrs_lib/include/mrs_lib/timeout_manager.h.func-sort-c.html @@ -0,0 +1,72 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/timeout_manager.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - timeout_manager.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:00-
+
+ +
+ + + + + + +

Function Name Sort by function nameHit count Sort by hit count
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/timeout_manager.h.func.html b/mrs_lib/include/mrs_lib/timeout_manager.h.func.html new file mode 100644 index 0000000000..0b90d80e54 --- /dev/null +++ b/mrs_lib/include/mrs_lib/timeout_manager.h.func.html @@ -0,0 +1,72 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/timeout_manager.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - timeout_manager.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:00-
+
+ +
+ + + + + + +

Function Name Sort by function nameHit count Sort by hit count
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/timeout_manager.h.gcov.html b/mrs_lib/include/mrs_lib/timeout_manager.h.gcov.html new file mode 100644 index 0000000000..05eb983ae5 --- /dev/null +++ b/mrs_lib/include/mrs_lib/timeout_manager.h.gcov.html @@ -0,0 +1,161 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/timeout_manager.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - timeout_manager.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:00-
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : /**  \file
+       3             :      \brief TODO
+       4             :      \author Matouš Vrba - vrbamato@fel.cvut.cz
+       5             :  */
+       6             : 
+       7             : #ifndef TIMEOUT_MANAGER_H
+       8             : #define TIMEOUT_MANAGER_H
+       9             : 
+      10             : #include <ros/ros.h>
+      11             : 
+      12             : namespace mrs_lib
+      13             : {
+      14             :   /* TimeoutManager class //{ */
+      15             :   /**
+      16             :   * \brief TODO
+      17             :   *
+      18             :   */
+      19             :   class TimeoutManager
+      20             :   {
+      21             :     public:
+      22             :       // | ---------------------- public types ---------------------- |
+      23             :       using timeout_id_t = size_t;
+      24             :       using callback_t = std::function<void(const ros::Time&)>;
+      25             : 
+      26             :     public:
+      27             :       // | --------------------- public methods --------------------- |
+      28             : 
+      29             :     /*!
+      30             :       * \brief TODO
+      31             :       *
+      32             :       */
+      33             :       TimeoutManager(const ros::NodeHandle& nh, const ros::Rate& update_rate);
+      34             : 
+      35           1 :       timeout_id_t registerNew(const ros::Duration& timeout, const callback_t& callback, const ros::Time& last_reset = ros::Time::now(), const bool oneshot = false, const bool autostart = true);
+      36             : 
+      37          20 :       void reset(const timeout_id_t id, const ros::Time& time = ros::Time::now());
+      38             : 
+      39             :       void pause(const timeout_id_t id);
+      40             : 
+      41           5 :       void start(const timeout_id_t id, const ros::Time& time = ros::Time::now());
+      42             : 
+      43             :       void pauseAll();
+      44             : 
+      45           2 :       void startAll(const ros::Time& time = ros::Time::now());
+      46             : 
+      47             :       void change(const timeout_id_t id, const ros::Duration& timeout, const callback_t& callback, const ros::Time& last_reset = ros::Time::now(), const bool oneshot = false, const bool autostart = true);
+      48             : 
+      49             :       ros::Time lastReset(const timeout_id_t id);
+      50             : 
+      51             :       bool started(const timeout_id_t id);
+      52             : 
+      53             :       /* implementation details //{ */
+      54             :       
+      55             :       private:
+      56             :         // | ---------------------- private types --------------------- |
+      57             :         struct timeout_info_t
+      58             :         {
+      59             :           bool oneshot;
+      60             :           bool started;
+      61             :           callback_t callback;
+      62             :           ros::Duration timeout;
+      63             :           ros::Time last_reset;
+      64             :           ros::Time last_callback;
+      65             :         };
+      66             :       
+      67             :       private:
+      68             :         // | --------------------- private methods -------------------- |
+      69             :         void main_timer_callback([[maybe_unused]] const ros::TimerEvent& evt);
+      70             :       
+      71             :       private:
+      72             :         // | ------------------------- members ------------------------ |
+      73             :         std::recursive_mutex m_mtx;
+      74             :         timeout_id_t m_last_id;
+      75             :         std::vector<timeout_info_t> m_timeouts;
+      76             :       
+      77             :         ros::Timer m_main_timer;
+      78             :       
+      79             :       //}
+      80             : 
+      81             :   };
+      82             :   //}
+      83             : }
+      84             : 
+      85             : #endif // TIMEOUT_MANAGER_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/timer.h.func-sort-c.html b/mrs_lib/include/mrs_lib/timer.h.func-sort-c.html new file mode 100644 index 0000000000..327403a9ca --- /dev/null +++ b/mrs_lib/include/mrs_lib/timer.h.func-sort-c.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/timer.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - timer.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:6785.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8MRSTimerD0Ev0
_ZN7mrs_lib11ThreadTimerD0Ev8
_ZN7mrs_lib11ThreadTimerD2Ev8
_ZN7mrs_lib8ROSTimerD0Ev8
_ZN7mrs_lib8ROSTimerD2Ev8
_ZN7mrs_lib8MRSTimerC2Ev16
_ZN7mrs_lib8MRSTimerD2Ev16
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/timer.h.func.html b/mrs_lib/include/mrs_lib/timer.h.func.html new file mode 100644 index 0000000000..9b7b4f837b --- /dev/null +++ b/mrs_lib/include/mrs_lib/timer.h.func.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/timer.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - timer.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:6785.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11ThreadTimerD0Ev8
_ZN7mrs_lib11ThreadTimerD2Ev8
_ZN7mrs_lib8MRSTimerC2Ev16
_ZN7mrs_lib8MRSTimerD0Ev0
_ZN7mrs_lib8MRSTimerD2Ev16
_ZN7mrs_lib8ROSTimerD0Ev8
_ZN7mrs_lib8ROSTimerD2Ev8
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/timer.h.gcov.html b/mrs_lib/include/mrs_lib/timer.h.gcov.html new file mode 100644 index 0000000000..e4606b0dd4 --- /dev/null +++ b/mrs_lib/include/mrs_lib/timer.h.gcov.html @@ -0,0 +1,320 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/timer.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - timer.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:6785.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef MRS_TIMER_H
+       2             : #define MRS_TIMER_H
+       3             : 
+       4             : #include <ros/ros.h>
+       5             : #include <thread>
+       6             : #include <mutex>
+       7             : #include <condition_variable>
+       8             : #include <atomic>
+       9             : 
+      10             : namespace mrs_lib
+      11             : {
+      12             :   bool breakable_sleep(const ros::Duration& dur, const std::atomic<bool>& continue_sleep);
+      13             : 
+      14             :   /**
+      15             :    * @brief Common wrapper representing the functionality of the ros::Timer.
+      16             :    *
+      17             :    * The implementation can then use either ros::Timer (the ROSTimer class)
+      18             :    * or threads and synchronization primitives from the C++ standard library
+      19             :    * (the ThreadTimer class). Both these variants implement the same interface.
+      20             :    *
+      21             :    * @note Functionality of the two implementations differs in some details.
+      22             :    */
+      23             :   class MRSTimer
+      24             :   {
+      25             :     public:
+      26             :     using callback_t = std::function<void(const ros::TimerEvent&)>;
+      27             : 
+      28             :     /**
+      29             :      * @brief stop the timer
+      30             :      */
+      31             :     virtual void stop() = 0;
+      32             : 
+      33             :     /**
+      34             :      * @brief start the timer
+      35             :      */
+      36             :     virtual void start() = 0;
+      37             : 
+      38             :     /**
+      39             :      * @brief set the timer period/duration
+      40             :      *
+      41             :      * @param duration
+      42             :      * @param reset
+      43             :      */
+      44             :     virtual void setPeriod(const ros::Duration& duration, const bool reset = true) = 0;
+      45             : 
+      46             :     /**
+      47             :      * @brief returns true if callbacks should be called
+      48             :      *
+      49             :      * @return true if timer is running
+      50             :      */
+      51             :     virtual bool running() = 0;
+      52             : 
+      53          16 :     virtual ~MRSTimer() = default;
+      54             :     MRSTimer(const MRSTimer&) = default;
+      55             :     MRSTimer(MRSTimer&&) = default;
+      56             :     MRSTimer& operator=(const MRSTimer&) = default;
+      57             :     MRSTimer& operator=(MRSTimer&&) = default;
+      58             : 
+      59             :     protected:
+      60          16 :     MRSTimer() = default;
+      61             :   };
+      62             : 
+      63             :   // | ------------------------ ROSTimer ------------------------ |
+      64             : 
+      65             :   /* class ROSTimer //{ */
+      66             : 
+      67             :   /**
+      68             :    * @brief ros::Timer wrapper. The interface is the same as with ros::Timer, except for the initialization method.
+      69             :    */
+      70             :   class ROSTimer : public MRSTimer {
+      71             :   public:
+      72             :     ROSTimer();
+      73             : 
+      74             :     /**
+      75             :      * @brief Constructs the object.
+      76             :      *
+      77             :      * @tparam ObjectType
+      78             :      * @param nh                            ROS node handle to be used for creating the underlying ros::Timer object.
+      79             :      * @param rate                          rate at which the callback should be called.
+      80             :      * @param ObjectType::*const callback   callback method to be called.
+      81             :      * @param obj                           object for the method.
+      82             :      * @param oneshot                       whether the callback should only be called once after starting.
+      83             :      * @param autostart                     whether the timer should immediately start after construction.
+      84             :      */
+      85             :     template <class ObjectType>
+      86             :     ROSTimer(const ros::NodeHandle& nh, const ros::Rate& rate, void (ObjectType::*const callback)(const ros::TimerEvent&), ObjectType* const obj,
+      87             :              const bool oneshot = false, const bool autostart = true);
+      88             : 
+      89             :     /**
+      90             :      * @brief full constructor
+      91             :      *
+      92             :      * @tparam ObjectType
+      93             :      * @param nh                            ROS node handle to be used for creating the underlying ros::Timer object.
+      94             :      * @param duration                      desired callback period.
+      95             :      * @param ObjectType::*const callback   callback method to be called.
+      96             :      * @param obj                           object for the method.
+      97             :      * @param oneshot                       whether the callback should only be called once after starting.
+      98             :      * @param autostart                     whether the timer should immediately start after construction.
+      99             :      */
+     100             :     template <class ObjectType>
+     101             :     ROSTimer(const ros::NodeHandle& nh, const ros::Duration& duration, void (ObjectType::*const callback)(const ros::TimerEvent&), ObjectType* const obj,
+     102             :              const bool oneshot = false, const bool autostart = true);
+     103             : 
+     104             :     /**
+     105             :      * @brief stop the timer
+     106             :      */
+     107             :     virtual void stop() override;
+     108             : 
+     109             :     /**
+     110             :      * @brief start the timer
+     111             :      */
+     112             :     virtual void start() override;
+     113             : 
+     114             :     /**
+     115             :      * @brief set the timer period/duration
+     116             :      *
+     117             :      * @param duration
+     118             :      * @param reset
+     119             :      */
+     120             :     virtual void setPeriod(const ros::Duration& duration, const bool reset = true) override;
+     121             : 
+     122             :     /**
+     123             :      * @brief returns true if callbacks should be called
+     124             :      *
+     125             :      * @return true if timer is running
+     126             :      */
+     127             :     virtual bool running() override;
+     128             : 
+     129          16 :     virtual ~ROSTimer() override {stop();};
+     130             :     // to keep rule of five since we have a custom destructor
+     131             :     ROSTimer(const ROSTimer&) = delete;
+     132             :     ROSTimer(ROSTimer&&) = delete;
+     133             :     ROSTimer& operator=(const ROSTimer&) = delete;
+     134             :     ROSTimer& operator=(ROSTimer&&) = delete;
+     135             : 
+     136             :   private:
+     137             :     std::mutex mutex_timer_;
+     138             : 
+     139             :     std::unique_ptr<ros::Timer> timer_;
+     140             :   };
+     141             : 
+     142             :   //}
+     143             : 
+     144             :   // | ----------------------- ThreadTimer ---------------------- |
+     145             : 
+     146             :   /* class ThreadTimer //{ */
+     147             : 
+     148             :   /**
+     149             :    * @brief Custom thread-based Timers with the same interface as mrs_lib::ROSTimer.
+     150             :    */
+     151             :   class ThreadTimer : public MRSTimer {
+     152             : 
+     153             :   public:
+     154             :     ThreadTimer();
+     155             : 
+     156             :     /**
+     157             :      * @brief Constructs the object.
+     158             :      *
+     159             :      * @tparam ObjectType
+     160             :      * @param nh                            ignored (used just for consistency with ROSTimer)
+     161             :      * @param rate                          rate at which the callback should be called.
+     162             :      * @param ObjectType::*const callback   callback method to be called.
+     163             :      * @param obj                           object for the method.
+     164             :      * @param oneshot                       whether the callback should only be called once after starting.
+     165             :      * @param autostart                     whether the timer should immediately start after construction.
+     166             :      */
+     167             :     template <class ObjectType>
+     168             :     ThreadTimer(const ros::NodeHandle& nh, const ros::Rate& rate, void (ObjectType::*const callback)(const ros::TimerEvent&), ObjectType* const obj,
+     169             :                 const bool oneshot = false, const bool autostart = true);
+     170             : 
+     171             :     /**
+     172             :      * @brief Constructs the object.
+     173             :      *
+     174             :      * @tparam ObjectType
+     175             :      * @param nh                            ignored (used just for consistency with ROSTimer)
+     176             :      * @param duration                      desired callback period.
+     177             :      * @param ObjectType::*const callback   callback method to be called.
+     178             :      * @param obj                           object for the method.
+     179             :      * @param oneshot                       whether the callback should only be called once after starting.
+     180             :      * @param autostart                     whether the timer should immediately start after construction.
+     181             :      */
+     182             :     template <class ObjectType>
+     183             :     ThreadTimer(const ros::NodeHandle& nh, const ros::Duration& duration, void (ObjectType::*const callback)(const ros::TimerEvent&), ObjectType* const obj,
+     184             :                 bool oneshot = false, const bool autostart = true);
+     185             : 
+     186             :     /**
+     187             :      * @brief stop the timer
+     188             :      *
+     189             :      * No more callbacks will be called after this method returns.
+     190             :      */
+     191             :     virtual void stop() override;
+     192             : 
+     193             :     /**
+     194             :      * @brief start the timer
+     195             :      *
+     196             :      * The first callback will be called in now + period.
+     197             :      *
+     198             :      * @note If the timer is already started, nothing will change.
+     199             :      */
+     200             :     virtual void start() override;
+     201             : 
+     202             :     /**
+     203             :      * @brief set the timer period/duration
+     204             :      *
+     205             :      * The new period will be applied after the next callback.
+     206             :      *
+     207             :      * @param duration the new desired callback period.
+     208             :      * @param reset    ignored in this implementation.
+     209             :      */
+     210             :     virtual void setPeriod(const ros::Duration& duration, const bool reset = true) override;
+     211             : 
+     212             :     /**
+     213             :      * @brief returns true if callbacks should be called
+     214             :      *
+     215             :      * @return true if timer is running
+     216             :      */
+     217             :     virtual bool running() override;
+     218             : 
+     219             :     /**
+     220             :      * @brief stops the timer and then destroys the object
+     221             :      *
+     222             :      * No more callbacks will be called when the destructor is started.
+     223             :      */
+     224          16 :     virtual ~ThreadTimer() override {stop();};
+     225             :     // to keep rule of five since we have a custom destructor
+     226             :     ThreadTimer(const ThreadTimer&) = delete;
+     227             :     ThreadTimer(ThreadTimer&&) = delete;
+     228             :     ThreadTimer& operator=(const ThreadTimer&) = delete;
+     229             :     ThreadTimer& operator=(ThreadTimer&&) = delete;
+     230             : 
+     231             :   private:
+     232             :     class Impl;
+     233             : 
+     234             :     std::unique_ptr<Impl> impl_;
+     235             : 
+     236             :   };  // namespace mrs_lib
+     237             : 
+     238             :   //}
+     239             : 
+     240             : #include <mrs_lib/impl/timer.hpp>
+     241             : 
+     242             : }  // namespace mrs_lib
+     243             : 
+     244             : #endif  // MRS_TIMER_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/transformer.h.func-sort-c.html b/mrs_lib/include/mrs_lib/transformer.h.func-sort-c.html new file mode 100644 index 0000000000..6e016649bc --- /dev/null +++ b/mrs_lib/include/mrs_lib/transformer.h.func-sort-c.html @@ -0,0 +1,140 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/transformer.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - transformer.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:485784.2 %
Date:2023-11-29 14:09:54Functions:131776.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNS8_IKS9_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKSA_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer9transformIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNS8_IKS9_EERKN13geometry_msgs17TransformStamped_IS4_EE0
_ZN7mrs_lib11Transformer9transformIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKSA_RKN13geometry_msgs17TransformStamped_IS4_EE0
_ZN7mrs_lib11Transformer15setDefaultFrameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS8_IKS9_EESJ_RKN3ros4TimeE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNS8_IKS9_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKSA_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer17retryLookupNewestEb1
_ZN7mrs_lib11Transformer7inverseERKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer16setLookupTimeoutEN3ros8DurationE2
_ZN7mrs_lib11Transformer16setDefaultPrefixERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE12
_ZN7mrs_lib11Transformer16create_transformERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_RKN3ros4TimeERKN13geometry_msgs10Transform_ISaIvEEE52
_ZN7mrs_lib11Transformer10frame_fromB5cxx11ERN13geometry_msgs17TransformStamped_ISaIvEEE55
_ZN7mrs_lib11Transformer8frame_toB5cxx11ERN13geometry_msgs17TransformStamped_ISaIvEEE55
_ZN7mrs_lib11Transformer10frame_fromB5cxx11ERKN13geometry_msgs17TransformStamped_ISaIvEEE113
_ZN7mrs_lib11Transformer8frame_toB5cxx11ERKN13geometry_msgs17TransformStamped_ISaIvEEE113
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/transformer.h.func.html b/mrs_lib/include/mrs_lib/transformer.h.func.html new file mode 100644 index 0000000000..66db2e3a1c --- /dev/null +++ b/mrs_lib/include/mrs_lib/transformer.h.func.html @@ -0,0 +1,140 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/transformer.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - transformer.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:485784.2 %
Date:2023-11-29 14:09:54Functions:131776.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11Transformer10frame_fromB5cxx11ERKN13geometry_msgs17TransformStamped_ISaIvEEE113
_ZN7mrs_lib11Transformer10frame_fromB5cxx11ERN13geometry_msgs17TransformStamped_ISaIvEEE55
_ZN7mrs_lib11Transformer15setDefaultFrameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs11Quaternion_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS8_IKS9_EESJ_RKN3ros4TimeE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNS8_IKS9_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer15transformSingleIN13geometry_msgs13PointStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKSA_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE1
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNS8_IKS9_EERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer15transformSingleIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKSA_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer16create_transformERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_RKN3ros4TimeERKN13geometry_msgs10Transform_ISaIvEEE52
_ZN7mrs_lib11Transformer16setDefaultPrefixERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE12
_ZN7mrs_lib11Transformer16setLookupTimeoutEN3ros8DurationE2
_ZN7mrs_lib11Transformer17retryLookupNewestEb1
_ZN7mrs_lib11Transformer7inverseERKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer8frame_toB5cxx11ERKN13geometry_msgs17TransformStamped_ISaIvEEE113
_ZN7mrs_lib11Transformer8frame_toB5cxx11ERN13geometry_msgs17TransformStamped_ISaIvEEE55
_ZN7mrs_lib11Transformer9transformIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKNS8_IKS9_EERKN13geometry_msgs17TransformStamped_IS4_EE0
_ZN7mrs_lib11Transformer9transformIN8mrs_msgs17ReferenceStamped_ISaIvEEEEESt8optionalIN5boost10shared_ptrIT_EEERKSA_RKN13geometry_msgs17TransformStamped_IS4_EE0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/transformer.h.gcov.html b/mrs_lib/include/mrs_lib/transformer.h.gcov.html new file mode 100644 index 0000000000..d9e4ef0f04 --- /dev/null +++ b/mrs_lib/include/mrs_lib/transformer.h.gcov.html @@ -0,0 +1,756 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/transformer.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - transformer.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:485784.2 %
Date:2023-11-29 14:09:54Functions:131776.5 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : 
+       3             : /**  \file Implements the Transformer class - wrapper for ROS's TF2 lookups and transformations.
+       4             :  *   \brief A wrapper for easier work with tf2 transformations.
+       5             :  *   \author Tomas Baca - tomas.baca@fel.cvut.cz
+       6             :  *   \author Matouš Vrba - matous.vrba@fel.cvut.cz
+       7             :  */
+       8             : #ifndef TRANSFORMER_H
+       9             : #define TRANSFORMER_H
+      10             : 
+      11             : /* #define EIGEN_DONT_VECTORIZE */
+      12             : /* #define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT */
+      13             : 
+      14             : /* includes //{ */
+      15             : 
+      16             : #include <ros/ros.h>
+      17             : 
+      18             : #include <tf2_ros/transform_listener.h>
+      19             : #include <tf2_ros/buffer.h>
+      20             : #include <tf2_eigen/tf2_eigen.h>
+      21             : #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
+      22             : #include <tf/transform_datatypes.h>
+      23             : #include <tf_conversions/tf_eigen.h>
+      24             : 
+      25             : #include <mrs_msgs/ReferenceStamped.h>
+      26             : 
+      27             : #include <geometry_msgs/PoseStamped.h>
+      28             : #include <geometry_msgs/Vector3Stamped.h>
+      29             : #include <std_msgs/Header.h>
+      30             : 
+      31             : #include <mrs_lib/geometry/misc.h>
+      32             : 
+      33             : #include <pcl_ros/point_cloud.h>
+      34             : #include <pcl_ros/transforms.h>
+      35             : #include <pcl_conversions/pcl_conversions.h>
+      36             : 
+      37             : #include <mutex>
+      38             : #include <experimental/type_traits>
+      39             : 
+      40             : //}
+      41             : 
+      42             : namespace tf2
+      43             : {
+      44             : 
+      45             :   template <typename pt_t>
+      46             :   void doTransform(const pcl::PointCloud<pt_t>& cloud_in, pcl::PointCloud<pt_t>& cloud_out, const geometry_msgs::TransformStamped& transform)
+      47             :   {
+      48             :     pcl_ros::transformPointCloud(cloud_in, cloud_out, transform.transform);
+      49             :     pcl_conversions::toPCL(transform.header.stamp, cloud_out.header.stamp);
+      50             :     cloud_out.header.frame_id = transform.header.frame_id;
+      51             :   }
+      52             : 
+      53             : }  // namespace tf2
+      54             : 
+      55             : namespace mrs_lib
+      56             : {
+      57             : 
+      58             :   static const std::string UTM_ORIGIN = "utm_origin";
+      59             :   static const std::string LATLON_ORIGIN = "latlon_origin";
+      60             : 
+      61             :   /**
+      62             :    * \brief A convenience wrapper class for ROS's native TF2 API to simplify transforming of various messages.
+      63             :    *
+      64             :    * Implements optional automatic frame prefix deduction, seamless transformation lattitude/longitude coordinates and UTM coordinates, simple transformation of MRS messages etc.
+      65             :    */
+      66             :   /* class Transformer //{ */
+      67             : 
+      68             :   class Transformer
+      69             :   {
+      70             : 
+      71             :   public:
+      72             :     /* Constructor, assignment operator and overloads //{ */
+      73             : 
+      74             :     /**
+      75             :      * \brief A convenience constructor that doesn't initialize anything.
+      76             :      *
+      77             :      * This constructor is just to enable usign the Transformer as a member variable of nodelets etc.
+      78             :      * To actually initialize the class, use the alternative constructor.
+      79             :      *
+      80             :      * \note This constructor doesn't initialize the TF2 transform listener and all calls to the transformation-related methods of an object constructed using this method will fail.
+      81             :      */
+      82             :     Transformer();
+      83             : 
+      84             :     /**
+      85             :      * \brief The main constructor that actually initializes stuff.
+      86             :      *
+      87             :      * This constructor initializes the class and the TF2 transform listener.
+      88             :      *
+      89             :      * \param node_name   the name of the node running the transformer, is used in ROS prints. If you don't care, just set it to an empty string.
+      90             :      * \param cache_time  duration of the transformation buffer's cache into the past that will be kept.
+      91             :      */
+      92             :     Transformer(const std::string& node_name, const ros::Duration& cache_time = ros::Duration(tf2_ros::Buffer::DEFAULT_CACHE_TIME));
+      93             : 
+      94             :     /**
+      95             :      * \brief The main constructor that actually initializes stuff.
+      96             :      *
+      97             :      * This constructor initializes the class and the TF2 transform listener.
+      98             :      *
+      99             :      * \param nh          the node handle to be used for subscribing to the transformations.
+     100             :      * \param node_name   the name of the node running the transformer, is used in ROS prints. If you don't care, just set it to an empty string.
+     101             :      * \param cache_time  duration of the transformation buffer's cache into the past that will be kept.
+     102             :      */
+     103             :     Transformer(const ros::NodeHandle& nh, const std::string& node_name = std::string(), const ros::Duration& cache_time = ros::Duration(tf2_ros::Buffer::DEFAULT_CACHE_TIME));
+     104             : 
+     105             :     /**
+     106             :      * \brief A convenience move assignment operator.
+     107             :      *
+     108             :      * This operator moves all data from the object that is being assigned from, invalidating it.
+     109             :      *
+     110             :      * \param  other  the object to assign from. It will be invalid after this method returns.
+     111             :      * \return        a reference to the object being assigned to.
+     112             :      */
+     113             :     Transformer& operator=(Transformer&& other);
+     114             : 
+     115             :     //}
+     116             : 
+     117             :     // | ------------------ Configuration methods ----------------- |
+     118             : 
+     119             :     /* setDefaultFrame() //{ */
+     120             : 
+     121             :     /**
+     122             :      * \brief Sets the default frame ID to be used instead of any empty frame ID.
+     123             :      *
+     124             :      * If you call e.g. the transform() method with a message that has an empty header.frame_id field, this value will be used instead.
+     125             :      *
+     126             :      * \param frame_id the default frame ID. Use an empty string to disable default frame ID deduction.
+     127             :      *
+     128             :      * \note Disabled by default.
+     129             :      */
+     130           1 :     void setDefaultFrame(const std::string& frame_id)
+     131             :     {
+     132           2 :       std::scoped_lock lck(mutex_);
+     133           1 :       default_frame_id_ = frame_id;
+     134           1 :     }
+     135             : 
+     136             :     //}
+     137             : 
+     138             :     /* setDefaultPrefix() //{ */
+     139             : 
+     140             :     /**
+     141             :      * \brief Sets the default frame ID prefix to be used if no prefix is present in the frame.
+     142             :      *
+     143             :      * If you call any method with a frame ID that doesn't begin with this string, it will be automatically prefixed including a forward slash between the prefix and raw frame ID.
+     144             :      * The forward slash should therefore *not* be included in the prefix.
+     145             :      *
+     146             :      * Example frame ID resolution assuming default prefix is "uav1":
+     147             :      *   "local_origin" -> "uav1/local_origin"
+     148             :      *
+     149             :      * \param prefix the default frame ID prefix (without the forward slash at the end). Use an empty string to disable default frame ID prefixing.
+     150             :      *
+     151             :      * \note Disabled by default. The prefix will be applied as a namespace (with a forward slash between the prefix and raw frame ID).
+     152             :      */
+     153          12 :     void setDefaultPrefix(const std::string& prefix)
+     154             :     {
+     155          24 :       std::scoped_lock lck(mutex_);
+     156          12 :       if (prefix.empty())
+     157           1 :         prefix_ = "";
+     158             :       else
+     159          11 :         prefix_ = prefix + "/";
+     160          12 :     }
+     161             : 
+     162             :     //}
+     163             : 
+     164             :     /* setLatLon() //{ */
+     165             : 
+     166             :     /**
+     167             :      * \brief Sets the curret lattitude and longitude for UTM zone calculation.
+     168             :      *
+     169             :      * The Transformer uses this to deduce the current UTM zone used for transforming stuff to latlon_origin.
+     170             :      *
+     171             :      * \param lat the latitude in degrees.
+     172             :      * \param lon the longitude in degrees.
+     173             :      *
+     174             :      * \note Any transformation to latlon_origin will fail if this function is not called first!
+     175             :      */
+     176             :     void setLatLon(const double lat, const double lon);
+     177             : 
+     178             :     //}
+     179             : 
+     180             :     /* setLookupTimeout() //{ */
+     181             : 
+     182             :     /**
+     183             :      * \brief Set a timeout for transform lookup.
+     184             :      *
+     185             :      * The transform lookup operation will block up to this duration if the transformation is not available immediately.
+     186             :      *
+     187             :      * \note Disabled by default.
+     188             :      *
+     189             :      * \param timeout the lookup timeout. Set to zero to disable blocking.
+     190             :      */
+     191           2 :     void setLookupTimeout(const ros::Duration timeout = ros::Duration(0))
+     192             :     {
+     193           2 :       std::scoped_lock lck(mutex_);
+     194           2 :       lookup_timeout_ = timeout;
+     195           2 :     }
+     196             : 
+     197             :     //}
+     198             : 
+     199             :     /* retryLookupNewest() //{ */
+     200             : 
+     201             :     /**
+     202             :      * \brief Enable/disable retry of a failed transform lookup with \p ros::Time(0).
+     203             :      *
+     204             :      * If enabled, a failed transform lookup will be retried.
+     205             :      * The new try will ignore the requested timestamp and will attempt to fetch the latest transformation between the two frames.
+     206             :      *
+     207             :      * \note Disabled by default.
+     208             :      *
+     209             :      * \param retry enables or disables retry.
+     210             :      */
+     211           1 :     void retryLookupNewest(const bool retry = true)
+     212             :     {
+     213           1 :       std::scoped_lock lck(mutex_);
+     214           1 :       retry_lookup_newest_ = retry;
+     215           1 :     }
+     216             : 
+     217             :     //}
+     218             :     
+     219             :     /* beQuiet() //{ */
+     220             : 
+     221             :     /**
+     222             :      * \brief Enable/disable some prints that may be too noisy.
+     223             :      *
+     224             :      * \param quiet enables or disables quiet mode.
+     225             :      *
+     226             :      * \note Disabled by default.
+     227             :      */
+     228             :     void beQuiet(const bool quiet = true)
+     229             :     {
+     230             :       std::scoped_lock lck(mutex_);
+     231             :       quiet_ = quiet;
+     232             :     }
+     233             : 
+     234             :     //}
+     235             : 
+     236             :     /* resolveFrame() //{ */
+     237             :     /**
+     238             :      * \brief Deduce the full frame ID from a shortened or empty string using current default prefix and default frame rules.
+     239             :      *
+     240             :      * Example assuming default prefix is "uav1" and default frame is "uav1/gps_origin":
+     241             :      *   "" -> "uav1/gps_origin"
+     242             :      *   "local_origin" -> "uav1/local_origin"
+     243             :      *
+     244             :      * \param frame_id The frame ID to be resolved.
+     245             :      *
+     246             :      * \return The resolved frame ID.
+     247             :      */
+     248             :     std::string resolveFrame(const std::string& frame_id)
+     249             :     {
+     250             :       std::scoped_lock lck(mutex_);
+     251             :       return resolveFrameImpl(frame_id);
+     252             :     }
+     253             :     //}
+     254             : 
+     255             :     /* transformSingle() //{ */
+     256             : 
+     257             :     /**
+     258             :      * \brief Transforms a single variable to a new frame and returns it or \p std::nullopt if transformation fails.
+     259             :      *
+     260             :      * \param what the object to be transformed.
+     261             :      * \param to_frame the target frame ID.
+     262             :      *
+     263             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     264             :      */
+     265             :     template <class T>
+     266             :     [[nodiscard]] std::optional<T> transformSingle(const T& what, const std::string& to_frame);
+     267             : 
+     268             :     /**
+     269             :      * \brief Transforms a single variable to a new frame.
+     270             :      *
+     271             :      * A convenience override for shared pointers.
+     272             :      *
+     273             :      * \param what The object to be transformed.
+     274             :      * \param to_frame The target fram ID.
+     275             :      *
+     276             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     277             :      */
+     278             :     template <class T>
+     279           1 :     [[nodiscard]] std::optional<boost::shared_ptr<T>> transformSingle(const boost::shared_ptr<T>& what, const std::string& to_frame)
+     280             :     {
+     281           1 :       return transformSingle(boost::shared_ptr<const T>(what), to_frame);
+     282             :     }
+     283             : 
+     284             :     /**
+     285             :      * \brief Transforms a single variable to a new frame.
+     286             :      *
+     287             :      * A convenience override for shared pointers to const.
+     288             :      *
+     289             :      * \param what The object to be transformed.
+     290             :      * \param to_frame The target fram ID.
+     291             :      *
+     292             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     293             :      */
+     294             :     template <class T>
+     295           1 :     [[nodiscard]] std::optional<boost::shared_ptr<T>> transformSingle(const boost::shared_ptr<const T>& what, const std::string& to_frame)
+     296             :     {
+     297           2 :       auto ret = transformSingle(*what, to_frame);
+     298           1 :       if (ret == std::nullopt)
+     299           0 :         return std::nullopt;
+     300             :       else
+     301           1 :         return boost::make_shared<T>(std::move(ret.value()));
+     302             :     }
+     303             : 
+     304             :     /**
+     305             :      * \brief Transforms a single variable to a new frame and returns it or \p std::nullopt if transformation fails.
+     306             :      *
+     307             :      * A convenience overload for headerless variables.
+     308             :      *
+     309             :      * \param from_frame the original target frame ID.
+     310             :      * \param what the object to be transformed.
+     311             :      * \param to_frame the target frame ID.
+     312             :      * \param time_stamp the time of the transformation.
+     313             :      *
+     314             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     315             :      */
+     316             :     template <class T>
+     317             :     [[nodiscard]] std::optional<T> transformSingle(const std::string& from_frame, const T& what, const std::string& to_frame, const ros::Time& time_stamp = ros::Time(0));
+     318             : 
+     319             :     /**
+     320             :      * \brief Transforms a single variable to a new frame and returns it or \p std::nullopt if transformation fails.
+     321             :      *
+     322             :      * A convenience overload for shared pointers to headerless variables.
+     323             :      *
+     324             :      * \param from_frame the original target frame ID.
+     325             :      * \param what the object to be transformed.
+     326             :      * \param to_frame the target frame ID.
+     327             :      * \param time_stamp the time of the transformation.
+     328             :      *
+     329             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     330             :      */
+     331             :     template <class T>
+     332             :     [[nodiscard]] std::optional<boost::shared_ptr<T>> transformSingle(const std::string& from_frame, const boost::shared_ptr<T>& what, const std::string& to_frame, const ros::Time& time_stamp = ros::Time(0))
+     333             :     {
+     334             :       return transformSingle(from_frame, boost::shared_ptr<const T>(what), to_frame, time_stamp);
+     335             :     }
+     336             : 
+     337             :     /**
+     338             :      * \brief Transforms a single variable to a new frame and returns it or \p std::nullopt if transformation fails.
+     339             :      *
+     340             :      * A convenience overload for shared pointers to const headerless variables.
+     341             :      *
+     342             :      * \param from_frame the original target frame ID.
+     343             :      * \param what the object to be transformed.
+     344             :      * \param to_frame the target frame ID.
+     345             :      * \param time_stamp the time of the transformation.
+     346             :      *
+     347             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     348             :      */
+     349             :     template <class T>
+     350           1 :     [[nodiscard]] std::optional<boost::shared_ptr<T>> transformSingle(const std::string& from_frame, const boost::shared_ptr<const T>& what, const std::string& to_frame, const ros::Time& time_stamp = ros::Time(0))
+     351             :     {
+     352           1 :       auto ret = transformSingle(from_frame, *what, to_frame, time_stamp);
+     353           1 :       if (ret == std::nullopt)
+     354           0 :         return std::nullopt;
+     355             :       else
+     356           1 :         return boost::make_shared<T>(std::move(ret.value()));
+     357             :     }
+     358             : 
+     359             :     //}
+     360             : 
+     361             :     /* transform() //{ */
+     362             : 
+     363             :     /**
+     364             :      * \brief Transform a variable to new frame using a particular transformation.
+     365             :      *
+     366             :      * \param tf The transformation to be used.
+     367             :      * \param what The object to be transformed.
+     368             :      *
+     369             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     370             :      */
+     371             :     template <class T>
+     372             :     [[nodiscard]] std::optional<T> transform(const T& what, const geometry_msgs::TransformStamped& tf);
+     373             : 
+     374             :     /**
+     375             :      * \brief Transform a variable to new frame using a particular transformation.
+     376             :      *
+     377             :      * A convenience override for shared pointers to const.
+     378             :      *
+     379             :      * \param tf The transformation to be used.
+     380             :      * \param what The object to be transformed.
+     381             :      *
+     382             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     383             :      */
+     384             :     template <class T>
+     385           0 :     [[nodiscard]] std::optional<boost::shared_ptr<T>> transform(const boost::shared_ptr<const T>& what, const geometry_msgs::TransformStamped& tf)
+     386             :     {
+     387           0 :       auto ret = transform(*what, tf);
+     388           0 :       if (ret == std::nullopt)
+     389           0 :         return std::nullopt;
+     390             :       else
+     391           0 :         return boost::make_shared<T>(std::move(ret.value()));
+     392             :     }
+     393             : 
+     394             :     /**
+     395             :      * \brief Transform a variable to new frame using a particular transformation.
+     396             :      *
+     397             :      * A convenience override for shared pointers.
+     398             :      *
+     399             :      * \param tf The transformation to be used.
+     400             :      * \param what The object to be transformed.
+     401             :      *
+     402             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     403             :      */
+     404             :     template <class T>
+     405           0 :     [[nodiscard]] std::optional<boost::shared_ptr<T>> transform(const boost::shared_ptr<T>& what, const geometry_msgs::TransformStamped& tf)
+     406             :     {
+     407           0 :       return transform(boost::shared_ptr<const T>(what), tf);
+     408             :     }
+     409             : 
+     410             :     //}
+     411             : 
+     412             :     /* transformAsVector() method //{ */
+     413             :     /**
+     414             :      * \brief Transform an Eigen::Vector3d (interpreting it as a vector).
+     415             :      *
+     416             :      * Only the rotation will be applied to the variable.
+     417             :      *
+     418             :      * \param tf The transformation to be used.
+     419             :      * \param what The vector to be transformed.
+     420             :      *
+     421             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     422             :      */
+     423             :     [[nodiscard]] std::optional<Eigen::Vector3d> transformAsVector(const Eigen::Vector3d& what, const geometry_msgs::TransformStamped& tf);
+     424             : 
+     425             :     /**
+     426             :      * \brief Transform an Eigen::Vector3d (interpreting it as a vector).
+     427             :      *
+     428             :      * Only the rotation will be applied to the variable.
+     429             :      *
+     430             :      * \param from_frame  The current frame of \p what.
+     431             :      * \param what        The vector to be transformed.
+     432             :      * \param to_frame    The desired frame of \p what.
+     433             :      * \param time_stamp  From which time to take the transformation (use \p ros::Time(0) for the latest time).
+     434             :      *
+     435             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     436             :      */
+     437             :     [[nodiscard]] std::optional<Eigen::Vector3d> transformAsVector(const std::string& from_frame, const Eigen::Vector3d& what, const std::string& to_frame, const ros::Time& time_stamp = ros::Time(0));
+     438             :     //}
+     439             : 
+     440             :     /* transformAsPoint() method //{ */
+     441             :     /**
+     442             :      * \brief Transform an Eigen::Vector3d (interpreting it as a point).
+     443             :      *
+     444             :      * Both the rotation and translation will be applied to the variable.
+     445             :      *
+     446             :      * \param tf The transformation to be used.
+     447             :      * \param what The object to be transformed.
+     448             :      *
+     449             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     450             :      */
+     451             :     [[nodiscard]] std::optional<Eigen::Vector3d> transformAsPoint(const Eigen::Vector3d& what, const geometry_msgs::TransformStamped& tf);
+     452             : 
+     453             :     /**
+     454             :      * \brief Transform an Eigen::Vector3d (interpreting it as a point).
+     455             :      *
+     456             :      * Both the rotation and translation will be applied to the variable.
+     457             :      *
+     458             :      * \param from_frame  The current frame of \p what.
+     459             :      * \param what The object to be transformed.
+     460             :      * \param to_frame    The desired frame of \p what.
+     461             :      * \param time_stamp  From which time to take the transformation (use \p ros::Time(0) for the latest time).
+     462             :      *
+     463             :      * \return \p std::nullopt if failed, optional containing the transformed object otherwise.
+     464             :      */
+     465             :     [[nodiscard]] std::optional<Eigen::Vector3d> transformAsPoint(const std::string& from_frame, const Eigen::Vector3d& what, const std::string& to_frame, const ros::Time& time_stamp = ros::Time(0));
+     466             :     //}
+     467             : 
+     468             :     /* getTransform() //{ */
+     469             : 
+     470             :     /**
+     471             :      * \brief Obtains a transform between two frames in a given time.
+     472             :      *
+     473             :      * \param from_frame The original frame of the transformation.
+     474             :      * \param to_frame The target frame of the transformation.
+     475             :      * \param time_stamp The time stamp of the transformation. (0 will get the latest)
+     476             :      *
+     477             :      * \return \p std::nullopt if failed, optional containing the requested transformation otherwise.
+     478             :      */
+     479             :     [[nodiscard]] std::optional<geometry_msgs::TransformStamped> getTransform(const std::string& from_frame, const std::string& to_frame, const ros::Time& time_stamp = ros::Time(0));
+     480             : 
+     481             :     /**
+     482             :      * \brief Obtains a transform between two frames in a given time.
+     483             :      *
+     484             :      * This overload enables the user to select a different time of the source frame and the target frame.
+     485             :      *
+     486             :      * \param from_frame The original frame of the transformation.
+     487             :      * \param from_stamp The time at which the original frame should be evaluated. (0 will get the latest)
+     488             :      * \param to_frame The target frame of the transformation.
+     489             :      * \param to_stamp The time to which the data should be transformed. (0 will get the latest) 
+     490             :      * \param fixed_frame The frame that may be assumed constant in time (the "world" frame).
+     491             :      *
+     492             :      * \return \p std::nullopt if failed, optional containing the requested transformation otherwise.
+     493             :      *
+     494             :      * \note An example of when this API may be useful is explained here: http://wiki.ros.org/tf2/Tutorials/Time%20travel%20with%20tf2%20%28C%2B%2B%29
+     495             :      */
+     496             :     [[nodiscard]] std::optional<geometry_msgs::TransformStamped> getTransform(const std::string& from_frame, const ros::Time& from_stamp, const std::string& to_frame, const ros::Time& to_stamp, const std::string& fixed_frame);
+     497             : 
+     498             :     //}
+     499             : 
+     500             :   private:
+     501             :     /* private members, methods etc //{ */
+     502             : 
+     503             :     std::mutex mutex_;
+     504             : 
+     505             :     // keeps track whether a non-basic constructor was called and the transform listener is initialized
+     506             :     bool initialized_ = false;
+     507             :     std::string node_name_;
+     508             : 
+     509             :     std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
+     510             :     std::unique_ptr<tf2_ros::TransformListener> tf_listener_ptr_;
+     511             : 
+     512             :     // user-configurable options
+     513             :     std::string default_frame_id_ = "";
+     514             :     std::string prefix_ = ""; // if not empty, includes the forward slash
+     515             :     bool quiet_ = false;
+     516             :     ros::Duration lookup_timeout_ = ros::Duration(0);
+     517             :     bool retry_lookup_newest_ = false;
+     518             : 
+     519             :     bool got_utm_zone_ = false;
+     520             :     std::array<char, 10> utm_zone_ = {};
+     521             : 
+     522             :     // returns the first namespace prefix of the frame (if any) includin the forward slash
+     523             :     std::string getFramePrefix(const std::string& frame_id);
+     524             : 
+     525             :     template <class T>
+     526             :     std::optional<T> transformImpl(const geometry_msgs::TransformStamped& tf, const T& what);
+     527             :     std::optional<mrs_msgs::ReferenceStamped> transformImpl(const geometry_msgs::TransformStamped& tf, const mrs_msgs::ReferenceStamped& what);
+     528             :     std::optional<Eigen::Vector3d> transformImpl(const geometry_msgs::TransformStamped& tf, const Eigen::Vector3d& what);
+     529             : 
+     530             :     [[nodiscard]] std::optional<geometry_msgs::TransformStamped> getTransformImpl(const std::string& from_frame, const std::string& to_frame, const ros::Time& time_stamp, const std::string& latlon_frame);
+     531             :     [[nodiscard]] std::optional<geometry_msgs::TransformStamped> getTransformImpl(const std::string& from_frame, const ros::Time& from_stamp, const std::string& to_frame, const ros::Time& to_stamp, const std::string& fixed_frame, const std::string& latlon_frame);
+     532             : 
+     533             :     std::string resolveFrameImpl(const std::string& frame_id);
+     534             : 
+     535             :     template <class T>
+     536             :     std::optional<T> doTransform(const T& what, const geometry_msgs::TransformStamped& tf);
+     537             : 
+     538             :     //}
+     539             : 
+     540             :     // | ------------------- some helper methods ------------------ |
+     541             :   public:
+     542             :     /* frame_from(), frame_to() and inverse() methods //{ */
+     543             :     
+     544             :     /**
+     545             :      * \brief A convenience function that returns the frame from which the message transforms.
+     546             :      *
+     547             :      * \param msg the message representing the transformation.
+     548             :      * \return    the frame from which the transformation in \msg transforms.
+     549             :      */
+     550         113 :     static constexpr const std::string& frame_from(const geometry_msgs::TransformStamped& msg)
+     551             :     {
+     552         113 :       return msg.child_frame_id;
+     553             :     }
+     554             :     
+     555             :     /**
+     556             :      * \brief A convenience function that returns the frame from which the message transforms.
+     557             :      *
+     558             :      * This overload returns a reference to the string in the message representing the frame id so that it can be modified.
+     559             :      *
+     560             :      * \param msg the message representing the transformation.
+     561             :      * \return    a reference to the field in the message containing the string with the frame id from which the transformation in \msg transforms.
+     562             :      */
+     563          55 :     static constexpr std::string& frame_from(geometry_msgs::TransformStamped& msg)
+     564             :     {
+     565          55 :       return msg.child_frame_id;
+     566             :     }
+     567             :     
+     568             :     /**
+     569             :      * \brief A convenience function that returns the frame to which the message transforms.
+     570             :      *
+     571             :      * \param msg the message representing the transformation.
+     572             :      * \return    the frame to which the transformation in \msg transforms.
+     573             :      */
+     574         113 :     static constexpr const std::string& frame_to(const geometry_msgs::TransformStamped& msg)
+     575             :     {
+     576         113 :       return msg.header.frame_id;
+     577             :     }
+     578             : 
+     579             :     /**
+     580             :      * \brief A convenience function that returns the frame to which the message transforms.
+     581             :      *
+     582             :      * This overload returns a reference to the string in the message representing the frame id so that it can be modified.
+     583             :      *
+     584             :      * \param msg the message representing the transformation.
+     585             :      * \return    a reference to the field in the message containing the string with the frame id to which the transformation in \msg transforms.
+     586             :      */
+     587          55 :     static constexpr std::string& frame_to(geometry_msgs::TransformStamped& msg)
+     588             :     {
+     589          55 :       return msg.header.frame_id;
+     590             :     }
+     591             : 
+     592             :     /**
+     593             :      * \brief A convenience function implements returns the inverse of the transform message as a one-liner.
+     594             :      *
+     595             :      * \param msg the message representing the transformation.
+     596             :      * \return    a new message representing an inverse of the original transformation.
+     597             :      */
+     598           1 :     static geometry_msgs::TransformStamped inverse(const geometry_msgs::TransformStamped& msg)
+     599             :     {
+     600           1 :       tf2::Transform tf2;
+     601           1 :       tf2::fromMsg(msg.transform, tf2);
+     602           1 :       tf2 = tf2.inverse();
+     603           2 :       return create_transform(frame_to(msg), frame_from(msg), msg.header.stamp, tf2::toMsg(tf2));
+     604             :     }
+     605             :     //}
+     606             : 
+     607             :   private:
+     608             :     /* create_transform() method //{ */
+     609             :     static geometry_msgs::TransformStamped create_transform(const std::string& from_frame, const std::string& to_frame, const ros::Time& time_stamp)
+     610             :     {
+     611             :       geometry_msgs::TransformStamped ret;
+     612             :       frame_from(ret) = from_frame;
+     613             :       frame_to(ret) = to_frame;
+     614             :       ret.header.stamp = time_stamp;
+     615             :       return ret;
+     616             :     }
+     617             : 
+     618          52 :     static geometry_msgs::TransformStamped create_transform(const std::string& from_frame, const std::string& to_frame, const ros::Time& time_stamp, const geometry_msgs::Transform& tf)
+     619             :     {
+     620          52 :       geometry_msgs::TransformStamped ret;
+     621          52 :       frame_from(ret) = from_frame;
+     622          52 :       frame_to(ret) = to_frame;
+     623          52 :       ret.header.stamp = time_stamp;
+     624          52 :       ret.transform = tf;
+     625          52 :       return ret;
+     626             :     }
+     627             :     //}
+     628             : 
+     629             :     /* copyChangeFrame() and related methods //{ */
+     630             : 
+     631             :     // helper type and member for detecting whether a message has a header using SFINAE
+     632             :     template<typename T>
+     633             :     using has_header_member_chk = decltype( std::declval<T&>().header );
+     634             :     template<typename T>
+     635             :     static constexpr bool has_header_member_v = std::experimental::is_detected<has_header_member_chk, T>::value;
+     636             :     
+     637             :     template <typename msg_t>
+     638             :     std_msgs::Header getHeader(const msg_t& msg);
+     639             :     template <typename pt_t>
+     640             :     std_msgs::Header getHeader(const pcl::PointCloud<pt_t>& cloud);
+     641             :     
+     642             :     template <typename msg_t>
+     643             :     void setHeader(msg_t& msg, const std_msgs::Header& header);
+     644             :     template <typename pt_t>
+     645             :     void setHeader(pcl::PointCloud<pt_t>& cloud, const std_msgs::Header& header);
+     646             :     
+     647             :     template <typename T>
+     648             :     T copyChangeFrame(const T& what, const std::string& frame_id);
+     649             :     
+     650             :     //}
+     651             : 
+     652             :     /* methods for converting between lattitude/longitude and UTM coordinates //{ */
+     653             :     geometry_msgs::Point LLtoUTM(const geometry_msgs::Point& what, const std::string& prefix);
+     654             :     geometry_msgs::PointStamped LLtoUTM(const geometry_msgs::PointStamped& what, const std::string& prefix);
+     655             :     geometry_msgs::Pose LLtoUTM(const geometry_msgs::Pose& what, const std::string& prefix);
+     656             :     geometry_msgs::PoseStamped LLtoUTM(const geometry_msgs::PoseStamped& what, const std::string& prefix);
+     657             :     
+     658             :     std::optional<geometry_msgs::Point> UTMtoLL(const geometry_msgs::Point& what, const std::string& prefix);
+     659             :     std::optional<geometry_msgs::PointStamped> UTMtoLL(const geometry_msgs::PointStamped& what, const std::string& prefix);
+     660             :     std::optional<geometry_msgs::Pose> UTMtoLL(const geometry_msgs::Pose& what, const std::string& prefix);
+     661             :     std::optional<geometry_msgs::PoseStamped> UTMtoLL(const geometry_msgs::PoseStamped& what, const std::string& prefix);
+     662             :     
+     663             :     // helper types and member for detecting whether the UTMtoLL and LLtoUTM methods are defined for a certain message
+     664             :     template<class Class, typename Message>
+     665             :     using UTMLL_method_chk = decltype(std::declval<Class>().UTMtoLL(std::declval<const Message&>(), ""));
+     666             :     template<class Class, typename Message>
+     667             :     using LLUTM_method_chk = decltype(std::declval<Class>().LLtoUTM(std::declval<const Message&>(), ""));
+     668             :     template<class Class, typename Message>
+     669             :     static constexpr bool UTMLL_exists_v = std::experimental::is_detected<UTMLL_method_chk, Class, Message>::value && std::experimental::is_detected<LLUTM_method_chk, Class, Message>::value;
+     670             :     //}
+     671             : 
+     672             :   };
+     673             : 
+     674             :   //}
+     675             : 
+     676             : }  // namespace mrs_lib
+     677             : 
+     678             : #include <mrs_lib/impl/transformer.hpp>
+     679             : 
+     680             : #endif  // TRANSFORMER_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/ukf.h.func-sort-c.html b/mrs_lib/include/mrs_lib/ukf.h.func-sort-c.html new file mode 100644 index 0000000000..4c58ec5a8e --- /dev/null +++ b/mrs_lib/include/mrs_lib/ukf.h.func-sort-c.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/ukf.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - ukf.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:040.0 %
Date:2023-11-29 14:09:54Functions:020.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE17inverse_exception4whatEv0
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE21square_root_exception4whatEv0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/ukf.h.func.html b/mrs_lib/include/mrs_lib/ukf.h.func.html new file mode 100644 index 0000000000..800a59f565 --- /dev/null +++ b/mrs_lib/include/mrs_lib/ukf.h.func.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/ukf.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - ukf.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:040.0 %
Date:2023-11-29 14:09:54Functions:020.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE17inverse_exception4whatEv0
_ZNK7mrs_lib3UKFILi4ELi1ELi2EE21square_root_exception4whatEv0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/ukf.h.gcov.html b/mrs_lib/include/mrs_lib/ukf.h.gcov.html new file mode 100644 index 0000000000..073f5ccfce --- /dev/null +++ b/mrs_lib/include/mrs_lib/ukf.h.gcov.html @@ -0,0 +1,277 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/ukf.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - ukf.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:040.0 %
Date:2023-11-29 14:09:54Functions:020.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : #ifndef UKF_H
+       3             : #define UKF_H
+       4             : 
+       5             : /**  \file
+       6             :      \brief Defines UKF - a class implementing the Unscented Kalman Filter \cite UKF.
+       7             :      \author Tomáš Báča - bacatoma@fel.cvut.cz (original implementation)
+       8             :      \author Matouš Vrba - vrbamato@fel.cvut.cz (rewrite, documentation)
+       9             :  */
+      10             : 
+      11             : #include <mrs_lib/kalman_filter.h>
+      12             : 
+      13             : namespace mrs_lib
+      14             : {
+      15             : 
+      16             :   /**
+      17             :   * \brief Implementation of the Unscented Kalman filter \cite UKF.
+      18             :   *
+      19             :   * The Unscented Kalman filter (abbreviated UKF, \cite UKF) is a variant of the Kalman filter, which may be used
+      20             :   * for state filtration or estimation of non-linear systems as opposed to the Linear Kalman Filter
+      21             :   * (which is implemented in \ref LKF). The UKF tends to be more accurate than the simpler Extended Kalman Filter,
+      22             :   * espetially for highly non-linear systems. However, it is generally less stable than the LKF because of the extra
+      23             :   * matrix square root in the sigma points calculation, so it is recommended to use LKF for linear systems.
+      24             :   *
+      25             :   * The UKF C++ class itself is templated. This has its advantages and disadvantages. Main disadvantage is that it
+      26             :   * may be harder to use if you're not familiar with C++ templates, which, admittedly, can get somewhat messy,
+      27             :   * espetially during compilation. Another disadvantage is that if used unwisely, the compilation times can get
+      28             :   * much higher when using templates. The main advantage is compile-time checking (if it compiles, then it has
+      29             :   * a lower chance of crashing at runtime) and enabling more effective optimalizations during compilation. Also in case
+      30             :   * of Eigen, the code is arguably more readable when you use aliases to the specific Matrix instances instead of
+      31             :   * having Eigen::MatrixXd and Eigen::VectorXd everywhere.
+      32             :   *
+      33             :   * \tparam n_states         number of states of the system (length of the \f$ \mathbf{x} \f$ vector).
+      34             :   * \tparam n_inputs         number of inputs of the system (length of the \f$ \mathbf{u} \f$ vector).
+      35             :   * \tparam n_measurements   number of measurements of the system (length of the \f$ \mathbf{z} \f$ vector).
+      36             :   *
+      37             :   */
+      38             :   template <int n_states, int n_inputs, int n_measurements>
+      39             :   class UKF : KalmanFilter<n_states, n_inputs, n_measurements>
+      40             :   {
+      41             :   protected:
+      42             :     /* protected UKF definitions (typedefs, constants etc) //{ */
+      43             :     static constexpr int n = n_states;            /*!< \brief Length of the state vector of the system. */
+      44             :     static constexpr int m = n_inputs;            /*!< \brief Length of the input vector of the system. */
+      45             :     static constexpr int p = n_measurements;      /*!< \brief Length of the measurement vector of the system. */
+      46             :     static constexpr int w = 2 * n + 1;           /*!< \brief Number of sigma points/weights. */
+      47             : 
+      48             :     using Base_class = KalmanFilter<n, m, p>; /*!< \brief Base class of this class. */
+      49             : 
+      50             :     using X_t = typename Eigen::Matrix<double, n, w>;    /*!< \brief State sigma points matrix. */
+      51             :     using Z_t = typename Eigen::Matrix<double, p, w>;    /*!< \brief Measurement sigma points matrix. */
+      52             :     using Pzz_t = typename Eigen::Matrix<double, p, p>;  /*!< \brief Pzz helper matrix. */
+      53             :     using K_t = typename Eigen::Matrix<double, n, p>;    /*!< \brief Kalman gain matrix. */
+      54             :     //}
+      55             : 
+      56             :   public:
+      57             :     /* public UKF definitions (typedefs, constants etc) //{ */
+      58             :     //! state vector n*1 typedef
+      59             :     using x_t = typename Base_class::x_t;
+      60             :     //! input vector m*1 typedef
+      61             :     using u_t = typename Base_class::u_t;
+      62             :     //! measurement vector p*1 typedef
+      63             :     using z_t = typename Base_class::z_t;
+      64             :     //! state covariance n*n typedef
+      65             :     using P_t = typename Base_class::P_t;
+      66             :     //! measurement covariance p*p typedef
+      67             :     using R_t = typename Base_class::R_t;
+      68             :     //! process covariance n*n typedef
+      69             :     using Q_t = typename Base_class::Q_t;
+      70             :     //! weights vector (2n+1)*1 typedef
+      71             :     using W_t = typename Eigen::Matrix<double, w, 1>;
+      72             :     //! typedef of a helper struct for state and covariance
+      73             :     using statecov_t = typename Base_class::statecov_t;
+      74             :     //! function of the state transition model typedef
+      75             :     using transition_model_t = typename std::function<x_t(const x_t&, const u_t&, double)>;
+      76             :     //! function of the observation model typedef
+      77             :     using observation_model_t = typename std::function<z_t(const x_t&)>;
+      78             : 
+      79             :     //! is thrown when taking the square root of a matrix fails during sigma generation
+      80             :     struct square_root_exception : public std::exception
+      81             :     {
+      82           0 :       const char* what() const throw()
+      83             :       {
+      84           0 :         return "UKF: taking the square root of covariance update produced NANs!!!";
+      85             :       }
+      86             :     };
+      87             : 
+      88             :     //! is thrown when taking the inverse of a matrix fails during kalman gain calculation
+      89             :     struct inverse_exception : public std::exception
+      90             :     {
+      91           0 :       const char* what() const throw()
+      92             :       {
+      93           0 :         return "UKF: inverting of Pzz in correction update produced NANs!!!";
+      94             :       }
+      95             :     };
+      96             :     //}
+      97             : 
+      98             :   public:
+      99             :     /* UKF constructor //{ */
+     100             :   /*!
+     101             :     * \brief Convenience default constructor.
+     102             :     *
+     103             :     * This constructor should not be used if applicable. If used, the main constructor has to be called afterwards,
+     104             :     * otherwise the UKF object is invalid (not initialized).
+     105             :     */
+     106             :     UKF();
+     107             : 
+     108             :   /*!
+     109             :     * \brief The main constructor.
+     110             :     *
+     111             :     * \param alpha             Scaling parameter of the sigma generation (a small positive value, e.g. 1e-3).
+     112             :     * \param kappa             Secondary scaling parameter of the sigma generation (usually set to 0 or 1).
+     113             :     * \param beta              Incorporates prior knowledge about the distribution (for Gaussian distribution, 2 is optimal).
+     114             :     * \param transition_model  State transition model function.
+     115             :     * \param observation_model Observation model function.
+     116             :     */
+     117             :     UKF(const transition_model_t& transition_model, const observation_model_t& observation_model, const double alpha = 1e-3, const double kappa = 1, const double beta = 2);
+     118             :     //}
+     119             : 
+     120             :     /* correct() method //{ */
+     121             :   /*!
+     122             :     * \brief Implements the state correction step (measurement update).
+     123             :     *
+     124             :     * \param sc     Previous estimate of the state and covariance.
+     125             :     * \param z      Measurement vector.
+     126             :     * \param R      Measurement covariance matrix.
+     127             :     * \returns      The state and covariance after applying the correction step.
+     128             :     */
+     129             :     virtual statecov_t correct(const statecov_t& sc, const z_t& z, const R_t& R) const override;
+     130             :     //}
+     131             : 
+     132             :     /* predict() method //{ */
+     133             :   /*!
+     134             :     * \brief Implements the state prediction step (time update).
+     135             :     *
+     136             :     * \param sc     Previous estimate of the state and covariance.
+     137             :     * \param u      Input vector.
+     138             :     * \param Q      Process noise covariance matrix.
+     139             :     * \param dt     Duration since the previous estimate.
+     140             :     * \returns      The state and covariance after applying the correction step.
+     141             :     */
+     142             :     virtual statecov_t predict(const statecov_t& sc, const u_t& u, const Q_t& Q, double dt) const override;
+     143             :     //}
+     144             : 
+     145             :     /* setConstants() method //{ */
+     146             :   /*!
+     147             :     * \brief Changes the Unscented Transform parameters.
+     148             :     *
+     149             :     * \param alpha  Scaling parameter of the sigma generation (a small positive value - e.g. 1e-3).
+     150             :     * \param kappa  Secondary scaling parameter of the sigma generation (usually set to 0 or 1).
+     151             :     * \param beta   Incorporates prior knowledge about the distribution (for Gaussian distribution, 2 is optimal).
+     152             :     */
+     153             :     void setConstants(const double alpha, const double kappa, const double beta);
+     154             :     //}
+     155             : 
+     156             :     /* setTransitionModel() method //{ */
+     157             :   /*!
+     158             :     * \brief Changes the transition model function.
+     159             :     *
+     160             :     * \param transition_model   the new transition model
+     161             :     */
+     162             :     void setTransitionModel(const transition_model_t& transition_model);
+     163             :     //}
+     164             : 
+     165             :     /* setObservationModel() method //{ */
+     166             :   /*!
+     167             :     * \brief Changes the observation model function.
+     168             :     *
+     169             :     * \param observation_model   the new observation model
+     170             :     */
+     171             :     void setObservationModel(const observation_model_t& observation_model);
+     172             :     //}
+     173             : 
+     174             :   protected:
+     175             :     /* protected methods and member variables //{ */
+     176             : 
+     177             :     void computeWeights();
+     178             : 
+     179             :     X_t computeSigmas(const x_t& x, const P_t& P) const;
+     180             : 
+     181             :     P_t computePaSqrt(const P_t& P) const;
+     182             : 
+     183             :     Pzz_t computeInverse(const Pzz_t& Pzz) const;
+     184             : 
+     185             :     virtual K_t computeKalmanGain([[maybe_unused]] const x_t& x, [[maybe_unused]] const z_t& inn, const K_t& Pxz, const Pzz_t& Pzz) const;
+     186             : 
+     187             :     double m_alpha, m_kappa, m_beta, m_lambda;
+     188             :     W_t m_Wm;
+     189             :     W_t m_Wc;
+     190             : 
+     191             :     transition_model_t m_transition_model;
+     192             :     observation_model_t m_observation_model;
+     193             : 
+     194             :     //}
+     195             :   };
+     196             : 
+     197             : }  // namespace mrs_lib
+     198             : 
+     199             : #include <mrs_lib/impl/ukf.hpp>
+     200             : 
+     201             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/utils.h.func-sort-c.html b/mrs_lib/include/mrs_lib/utils.h.func-sort-c.html new file mode 100644 index 0000000000..e165ea879f --- /dev/null +++ b/mrs_lib/include/mrs_lib/utils.h.func-sort-c.html @@ -0,0 +1,92 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/utils.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - utils.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:1515100.0 %
Date:2023-11-29 14:09:54Functions:55100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib17containerToStringIN5boost5arrayIiLm3EEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_PKc1
_ZN7mrs_lib17containerToStringIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_SE_PKc1
_ZN7mrs_lib17containerToStringIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_SE_RKSD_1
_ZN7mrs_lib17containerToStringIPKiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_S9_RKS8_1
_ZN7mrs_lib6signumIdEEiT_63
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/utils.h.func.html b/mrs_lib/include/mrs_lib/utils.h.func.html new file mode 100644 index 0000000000..ca8b5f9d07 --- /dev/null +++ b/mrs_lib/include/mrs_lib/utils.h.func.html @@ -0,0 +1,92 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/utils.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - utils.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:1515100.0 %
Date:2023-11-29 14:09:54Functions:55100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib17containerToStringIN5boost5arrayIiLm3EEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_PKc1
_ZN7mrs_lib17containerToStringIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_SE_PKc1
_ZN7mrs_lib17containerToStringIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_SE_RKSD_1
_ZN7mrs_lib17containerToStringIPKiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_S9_RKS8_1
_ZN7mrs_lib6signumIdEEiT_63
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/include/mrs_lib/utils.h.gcov.html b/mrs_lib/include/mrs_lib/utils.h.gcov.html new file mode 100644 index 0000000000..3f26c9c37d --- /dev/null +++ b/mrs_lib/include/mrs_lib/utils.h.gcov.html @@ -0,0 +1,221 @@ + + + + + + + LCOV - coverage.info - mrs_lib/include/mrs_lib/utils.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/include/mrs_lib - utils.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:1515100.0 %
Date:2023-11-29 14:09:54Functions:55100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : /**  \file
+       3             :      \brief Defines various general utility functions.
+       4             :      \author Matouš Vrba - vrbamato@fel.cvut.cz
+       5             :      \author Viktor Walter - walver.viktor@fel.cvut.cz
+       6             :      \author Tomáš Báča - baca.tomas@fel.cvut.cz
+       7             :  */
+       8             : #ifndef UTILS_H
+       9             : #define UTILS_H
+      10             : 
+      11             : #include <iterator>
+      12             : #include <vector>
+      13             : #include <sstream>
+      14             : #include <atomic>
+      15             : 
+      16             : namespace mrs_lib
+      17             : {
+      18             :   /* containerToString() function //{ */
+      19             : 
+      20             :   /**
+      21             :    * \brief Convenience function for converting container ranges to strings (e.g. for printing).
+      22             :    *
+      23             :    * \param begin        first element of the container that will be converted to \p std::string.
+      24             :    * \param end          one-after-the-last element of the container that will be converted to \p std::string.
+      25             :    * \param delimiter    will be used to separate the elements in the output.
+      26             :    * \return             elements of the container from \p begin to \p end (excluding), converted to string and separated by \p delimiter.
+      27             :    *
+      28             :    */
+      29             :   template <typename Iterator>
+      30           2 :   std::string containerToString(const Iterator begin, const Iterator end, const std::string& delimiter = ", ")
+      31             :   {
+      32           2 :     bool first = true;
+      33           4 :     std::ostringstream output;
+      34           7 :     for (Iterator it = begin; it != end; it++)
+      35             :     {
+      36           5 :       if (!first)
+      37           3 :         output << delimiter;
+      38           5 :       output << *it;
+      39           5 :       first = false;
+      40             :     }
+      41           4 :     return output.str();
+      42             :   }
+      43             : 
+      44             :   /**
+      45             :    * \brief Convenience function for converting container ranges to strings (e.g. for printing).
+      46             :    *
+      47             :    * \param begin        first element of the container that will be converted to \p std::string.
+      48             :    * \param end          one-after-the-last element of the container that will be converted to \p std::string.
+      49             :    * \param delimiter    will be used to separate the elements in the output.
+      50             :    * \return             elements of the container from \p begin to \p end (excluding), converted to string and separated by \p delimiter.
+      51             :    *
+      52             :    */
+      53             :   template <typename Iterator>
+      54           1 :   std::string containerToString(const Iterator begin, const Iterator end, const char* delimiter)
+      55             :   {
+      56           1 :     return containerToString(begin, end, std::string(delimiter));
+      57             :   }
+      58             : 
+      59             :   /**
+      60             :    * \brief Convenience function for converting containers to strings (e.g. for printing).
+      61             :    *
+      62             :    * \param cont         the container that will be converted to \p std::string.
+      63             :    * \param delimiter    will be used to separate the elements in the output.
+      64             :    * \return             elements of the container from \p begin to \p end (excluding), converted to string and separated by \p delimiter.
+      65             :    *
+      66             :    */
+      67             :   template <typename Container>
+      68             :   std::string containerToString(const Container& cont, const std::string& delimiter = ", ")
+      69             :   {
+      70             :     return containerToString(std::begin(cont), std::end(cont), delimiter);
+      71             :   }
+      72             : 
+      73             :   /**
+      74             :    * \brief Convenience function for converting containers to strings (e.g. for printing).
+      75             :    *
+      76             :    * \param cont         the container that will be converted to \p std::string.
+      77             :    * \param delimiter    will be used to separate the elements in the output.
+      78             :    * \return             elements of the container from \p begin to \p end (excluding), converted to string and separated by \p delimiter.
+      79             :    *
+      80             :    */
+      81             :   template <typename Container>
+      82           1 :   std::string containerToString(const Container& cont, const char* delimiter = ", ")
+      83             :   {
+      84           1 :     return containerToString(std::begin(cont), std::end(cont), std::string(delimiter));
+      85             :   }
+      86             : 
+      87             :   //}
+      88             : 
+      89             :   /* remove_const() function //{ */
+      90             : 
+      91             :   /**
+      92             :    * \brief Convenience class for removing const-ness from a container iterator.
+      93             :    *
+      94             :    * \param it    the iterator from which const-ness should be removed.
+      95             :    * \param cont  the corresponding container of the iterator.
+      96             :    * \return      a non-const iterator, pointing to the same element as \p it.
+      97             :    *
+      98             :    */
+      99             :   template <typename T>
+     100             :   typename T::iterator remove_const(const typename T::const_iterator& it, T& cont)
+     101             :   {
+     102             :     typename T::iterator ret = cont.begin();
+     103             :     std::advance(ret, std::distance((typename T::const_iterator)ret, it));
+     104             :     return ret;
+     105             :   }
+     106             : 
+     107             :   //}
+     108             : 
+     109             :   /**
+     110             :    * \brief Convenience class for automatically setting and unsetting an atomic boolean based on the object's scope.
+     111             :    * Useful e.g. for indicating whether a thread is running or not.
+     112             :    *
+     113             :    */
+     114             :   class AtomicScopeFlag
+     115             :   {
+     116             : 
+     117             :   public:
+     118             :   /**
+     119             :    * \brief The constructor. Sets the flag \p in to \p true.
+     120             :    *
+     121             :    * \param in  The flag to be set on construction of this object and reset (set to \p false) on its destruction.
+     122             :    *
+     123             :    */
+     124             :     AtomicScopeFlag(std::atomic<bool>& in);
+     125             :   /**
+     126             :    * \brief The destructor. Resets the variable given in the constructor to \p false.
+     127             :    *
+     128             :    */
+     129             :     ~AtomicScopeFlag();
+     130             : 
+     131             :   private:
+     132             :     std::atomic<bool>& variable;
+     133             :   };
+     134             : 
+     135             :   // branchless, templated, more efficient version of the signum function
+     136             :   // taken from https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
+     137             :   template <typename T>
+     138          63 :   int signum(T val)
+     139             :   {
+     140          63 :     return (T(0) < val) - (val < T(0));
+     141             :   }
+     142             : 
+     143             : }  // namespace mrs_lib
+     144             : 
+     145             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/attitude_converter/attitude_converter.cpp.func-sort-c.html b/mrs_lib/src/attitude_converter/attitude_converter.cpp.func-sort-c.html new file mode 100644 index 0000000000..ddfbbd84bb --- /dev/null +++ b/mrs_lib/src/attitude_converter/attitude_converter.cpp.func-sort-c.html @@ -0,0 +1,236 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/attitude_converter/attitude_converter.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/attitude_converter - attitude_converter.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:20422491.1 %
Date:2023-11-29 14:09:54Functions:374190.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib16Vector3ConverterC2ERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZN7mrs_lib17AttitudeConverter6setYawERKd0
_ZNK7mrs_lib16Vector3ConvertercvN3tf27Vector3EEv0
_ZNK7mrs_lib17AttitudeConvertercvN3tf29TransformEEv0
_ZN7mrs_lib13EulerAttitudeC2ERKdS2_S2_1
_ZN7mrs_lib16Vector3ConverterC2ERKdS2_S2_1
_ZN7mrs_lib17AttitudeConverter15getExtrinsicRPYEv1
_ZN7mrs_lib17AttitudeConverter15getIntrinsicRPYEv1
_ZN7mrs_lib17AttitudeConverter6getYawEv1
_ZN7mrs_lib17AttitudeConverter7getRollEv1
_ZN7mrs_lib17AttitudeConverter8getPitchEv1
_ZN7mrs_lib17AttitudeConverterC2EN13geometry_msgs11Quaternion_ISaIvEEE1
_ZN7mrs_lib17AttitudeConverterC2EN2tf10QuaternionE1
_ZN7mrs_lib17AttitudeConverterC2EN3tf29Matrix3x3E1
_ZN7mrs_lib17AttitudeConverterC2EN5Eigen10QuaternionIdLi0EEE1
_ZN7mrs_lib17AttitudeConverterC2ERKNS_13EulerAttitudeE1
_ZN7mrs_lib17AttitudeConvertercvSt5tupleIJRdS2_S2_EEEv1
_ZNK7mrs_lib13EulerAttitude3yawEv1
_ZNK7mrs_lib13EulerAttitude4rollEv1
_ZNK7mrs_lib13EulerAttitude5pitchEv1
_ZNK7mrs_lib16Vector3ConvertercvN13geometry_msgs8Vector3_ISaIvEEEEv1
_ZNK7mrs_lib17AttitudeConvertercvN13geometry_msgs11Quaternion_ISaIvEEEEv1
_ZNK7mrs_lib17AttitudeConvertercvN2tf10QuaternionEEv1
_ZNK7mrs_lib17AttitudeConvertercvN3tf29Matrix3x3EEv1
_ZNK7mrs_lib17AttitudeConvertercvNS_13EulerAttitudeEEv1
_ZN7mrs_lib17AttitudeConverter10getVectorXEv3
_ZN7mrs_lib17AttitudeConverter10getVectorYEv3
_ZN7mrs_lib17AttitudeConverter12calculateRPYEv6
_ZN7mrs_lib17AttitudeConverter14getHeadingRateERKNS_16Vector3ConverterE63
_ZN7mrs_lib17AttitudeConverter19getYawRateIntrinsicERKd63
_ZN7mrs_lib16Vector3ConverterC2ERKN13geometry_msgs8Vector3_ISaIvEEE64
_ZNK7mrs_lib17AttitudeConvertercvN5Eigen6MatrixIdLi3ELi3ELi0ELi3ELi3EEEEv133
_ZN7mrs_lib17AttitudeConverter10setHeadingERKd1000
_ZN7mrs_lib17AttitudeConverterC2ERKdS2_S2_RKNS_16RPY_convention_tE1020
_ZN7mrs_lib17AttitudeConverterC2EN5Eigen6MatrixIdLi3ELi3ELi0ELi3ELi3EEE1192
_ZNK7mrs_lib17AttitudeConvertercvN3tf210QuaternionEEv2004
_ZN7mrs_lib17AttitudeConverter10getHeadingEv2062
_ZN7mrs_lib17AttitudeConverter10getVectorZEv3001
_ZNK7mrs_lib16Vector3ConvertercvN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEEv3071
_ZN7mrs_lib17AttitudeConverterC2EN3tf210QuaternionE5001
_ZN7mrs_lib17AttitudeConverter19validateOrientationEv7218
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/attitude_converter/attitude_converter.cpp.func.html b/mrs_lib/src/attitude_converter/attitude_converter.cpp.func.html new file mode 100644 index 0000000000..ea22369230 --- /dev/null +++ b/mrs_lib/src/attitude_converter/attitude_converter.cpp.func.html @@ -0,0 +1,236 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/attitude_converter/attitude_converter.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/attitude_converter - attitude_converter.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:20422491.1 %
Date:2023-11-29 14:09:54Functions:374190.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib13EulerAttitudeC2ERKdS2_S2_1
_ZN7mrs_lib16Vector3ConverterC2ERKN13geometry_msgs8Vector3_ISaIvEEE64
_ZN7mrs_lib16Vector3ConverterC2ERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZN7mrs_lib16Vector3ConverterC2ERKdS2_S2_1
_ZN7mrs_lib17AttitudeConverter10getHeadingEv2062
_ZN7mrs_lib17AttitudeConverter10getVectorXEv3
_ZN7mrs_lib17AttitudeConverter10getVectorYEv3
_ZN7mrs_lib17AttitudeConverter10getVectorZEv3001
_ZN7mrs_lib17AttitudeConverter10setHeadingERKd1000
_ZN7mrs_lib17AttitudeConverter12calculateRPYEv6
_ZN7mrs_lib17AttitudeConverter14getHeadingRateERKNS_16Vector3ConverterE63
_ZN7mrs_lib17AttitudeConverter15getExtrinsicRPYEv1
_ZN7mrs_lib17AttitudeConverter15getIntrinsicRPYEv1
_ZN7mrs_lib17AttitudeConverter19getYawRateIntrinsicERKd63
_ZN7mrs_lib17AttitudeConverter19validateOrientationEv7218
_ZN7mrs_lib17AttitudeConverter6getYawEv1
_ZN7mrs_lib17AttitudeConverter6setYawERKd0
_ZN7mrs_lib17AttitudeConverter7getRollEv1
_ZN7mrs_lib17AttitudeConverter8getPitchEv1
_ZN7mrs_lib17AttitudeConverterC2EN13geometry_msgs11Quaternion_ISaIvEEE1
_ZN7mrs_lib17AttitudeConverterC2EN2tf10QuaternionE1
_ZN7mrs_lib17AttitudeConverterC2EN3tf210QuaternionE5001
_ZN7mrs_lib17AttitudeConverterC2EN3tf29Matrix3x3E1
_ZN7mrs_lib17AttitudeConverterC2EN5Eigen10QuaternionIdLi0EEE1
_ZN7mrs_lib17AttitudeConverterC2EN5Eigen6MatrixIdLi3ELi3ELi0ELi3ELi3EEE1192
_ZN7mrs_lib17AttitudeConverterC2ERKNS_13EulerAttitudeE1
_ZN7mrs_lib17AttitudeConverterC2ERKdS2_S2_RKNS_16RPY_convention_tE1020
_ZN7mrs_lib17AttitudeConvertercvSt5tupleIJRdS2_S2_EEEv1
_ZNK7mrs_lib13EulerAttitude3yawEv1
_ZNK7mrs_lib13EulerAttitude4rollEv1
_ZNK7mrs_lib13EulerAttitude5pitchEv1
_ZNK7mrs_lib16Vector3ConvertercvN13geometry_msgs8Vector3_ISaIvEEEEv1
_ZNK7mrs_lib16Vector3ConvertercvN3tf27Vector3EEv0
_ZNK7mrs_lib16Vector3ConvertercvN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEEv3071
_ZNK7mrs_lib17AttitudeConvertercvN13geometry_msgs11Quaternion_ISaIvEEEEv1
_ZNK7mrs_lib17AttitudeConvertercvN2tf10QuaternionEEv1
_ZNK7mrs_lib17AttitudeConvertercvN3tf210QuaternionEEv2004
_ZNK7mrs_lib17AttitudeConvertercvN3tf29Matrix3x3EEv1
_ZNK7mrs_lib17AttitudeConvertercvN3tf29TransformEEv0
_ZNK7mrs_lib17AttitudeConvertercvN5Eigen6MatrixIdLi3ELi3ELi0ELi3ELi3EEEEv133
_ZNK7mrs_lib17AttitudeConvertercvNS_13EulerAttitudeEEv1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/attitude_converter/attitude_converter.cpp.gcov.html b/mrs_lib/src/attitude_converter/attitude_converter.cpp.gcov.html new file mode 100644 index 0000000000..5d35429760 --- /dev/null +++ b/mrs_lib/src/attitude_converter/attitude_converter.cpp.gcov.html @@ -0,0 +1,553 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/attitude_converter/attitude_converter.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/attitude_converter - attitude_converter.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:20422491.1 %
Date:2023-11-29 14:09:54Functions:374190.2 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: TomasFormat
+       2             : 
+       3             : #include <mrs_lib/attitude_converter.h>
+       4             : #include <mrs_lib/utils.h>
+       5             : 
+       6             : using quat_t = Eigen::Quaterniond;
+       7             : 
+       8             : namespace mrs_lib
+       9             : {
+      10             : 
+      11             : /* class EulerAttitude //{ */
+      12             : 
+      13           1 : EulerAttitude::EulerAttitude(const double& roll, const double& pitch, const double& yaw) : roll_(roll), pitch_(pitch), yaw_(yaw) {
+      14           1 : }
+      15             : 
+      16           1 : double EulerAttitude::roll(void) const {
+      17           1 :   return roll_;
+      18             : }
+      19             : 
+      20           1 : double EulerAttitude::pitch(void) const {
+      21           1 :   return pitch_;
+      22             : }
+      23             : 
+      24           1 : double EulerAttitude::yaw(void) const {
+      25           1 :   return yaw_;
+      26             : }
+      27             : 
+      28             : //}
+      29             : 
+      30             : /* class Vector3Converter //{ */
+      31             : 
+      32           0 : Vector3Converter::Vector3Converter(const Eigen::Vector3d& vector3) {
+      33             : 
+      34           0 :   vector3_[0] = vector3[0];
+      35           0 :   vector3_[1] = vector3[1];
+      36           0 :   vector3_[2] = vector3[2];
+      37           0 : }
+      38             : 
+      39          64 : Vector3Converter::Vector3Converter(const geometry_msgs::Vector3& vector3) {
+      40             : 
+      41          64 :   vector3_[0] = vector3.x;
+      42          64 :   vector3_[1] = vector3.y;
+      43          64 :   vector3_[2] = vector3.z;
+      44          64 : }
+      45             : 
+      46           1 : Vector3Converter::Vector3Converter(const double& x, const double& y, const double& z) {
+      47             : 
+      48           1 :   vector3_[0] = x;
+      49           1 :   vector3_[1] = y;
+      50           1 :   vector3_[2] = z;
+      51           1 : }
+      52             : 
+      53           0 : Vector3Converter::operator tf2::Vector3() const {
+      54             : 
+      55           0 :   return vector3_;
+      56             : }
+      57             : 
+      58        3071 : Vector3Converter::operator Eigen::Vector3d() const {
+      59             : 
+      60        3071 :   return Eigen::Vector3d(vector3_[0], vector3_[1], vector3_[2]);
+      61             : }
+      62             : 
+      63           1 : Vector3Converter::operator geometry_msgs::Vector3() const {
+      64             : 
+      65           1 :   geometry_msgs::Vector3 vector_3;
+      66             : 
+      67           1 :   vector_3.x = vector3_[0];
+      68           1 :   vector_3.y = vector3_[1];
+      69           1 :   vector_3.z = vector3_[2];
+      70             : 
+      71           1 :   return vector_3;
+      72             : }
+      73             : 
+      74             : //}
+      75             : 
+      76             : /* constructors //{ */
+      77             : 
+      78        1020 : AttitudeConverter::AttitudeConverter(const double& roll, const double& pitch, const double& yaw, const RPY_convention_t& format) {
+      79             : 
+      80        1020 :   switch (format) {
+      81             : 
+      82        1015 :     case RPY_EXTRINSIC: {
+      83        1015 :       tf2_quaternion_.setRPY(roll, pitch, yaw);
+      84        1015 :       break;
+      85             :     }
+      86             : 
+      87           5 :     case RPY_INTRINSIC: {
+      88             : 
+      89           5 :       Eigen::Matrix3d Y, P, R;
+      90             : 
+      91           5 :       Y << cos(yaw), -sin(yaw), 0, sin(yaw), cos(yaw), 0, 0, 0, 1;
+      92             : 
+      93           5 :       P << cos(pitch), 0, sin(pitch), 0, 1, 0, -sin(pitch), 0, cos(pitch);
+      94             : 
+      95           5 :       R << 1, 0, 0, 0, cos(roll), -sin(roll), 0, sin(roll), cos(roll);
+      96             : 
+      97           5 :       tf2_quaternion_ = AttitudeConverter(R * P * Y);
+      98             : 
+      99           5 :       break;
+     100             :     }
+     101             :   }
+     102             : 
+     103        1020 :   validateOrientation();
+     104        1018 : }
+     105             : 
+     106           1 : AttitudeConverter::AttitudeConverter(const tf::Quaternion quaternion) {
+     107             : 
+     108           1 :   tf2_quaternion_.setX(quaternion.x());
+     109           1 :   tf2_quaternion_.setY(quaternion.y());
+     110           1 :   tf2_quaternion_.setZ(quaternion.z());
+     111           1 :   tf2_quaternion_.setW(quaternion.w());
+     112             : 
+     113           1 :   validateOrientation();
+     114           1 : }
+     115             : 
+     116           1 : AttitudeConverter::AttitudeConverter(const geometry_msgs::Quaternion quaternion) {
+     117           1 :   tf2_quaternion_.setX(quaternion.x);
+     118           1 :   tf2_quaternion_.setY(quaternion.y);
+     119           1 :   tf2_quaternion_.setZ(quaternion.z);
+     120           1 :   tf2_quaternion_.setW(quaternion.w);
+     121             : 
+     122           1 :   validateOrientation();
+     123           1 : }
+     124             : 
+     125           1 : AttitudeConverter::AttitudeConverter(const mrs_lib::EulerAttitude& euler_attitude) {
+     126           1 :   tf2_quaternion_.setRPY(euler_attitude.roll(), euler_attitude.pitch(), euler_attitude.yaw());
+     127             : 
+     128           1 :   validateOrientation();
+     129           1 : }
+     130             : 
+     131           1 : AttitudeConverter::AttitudeConverter(const Eigen::Quaterniond quaternion) {
+     132           1 :   tf2_quaternion_.setX(quaternion.x());
+     133           1 :   tf2_quaternion_.setY(quaternion.y());
+     134           1 :   tf2_quaternion_.setZ(quaternion.z());
+     135           1 :   tf2_quaternion_.setW(quaternion.w());
+     136             : 
+     137           1 :   validateOrientation();
+     138           1 : }
+     139             : 
+     140        1192 : AttitudeConverter::AttitudeConverter(const Eigen::Matrix3d matrix) {
+     141        1192 :   Eigen::Quaterniond quaternion = Eigen::Quaterniond(matrix);
+     142             : 
+     143        1192 :   tf2_quaternion_.setX(quaternion.x());
+     144        1192 :   tf2_quaternion_.setY(quaternion.y());
+     145        1192 :   tf2_quaternion_.setZ(quaternion.z());
+     146        1192 :   tf2_quaternion_.setW(quaternion.w());
+     147             : 
+     148        1192 :   validateOrientation();
+     149        1192 : }
+     150             : 
+     151        5001 : AttitudeConverter::AttitudeConverter(const tf2::Quaternion quaternion) {
+     152             : 
+     153        5001 :   tf2_quaternion_ = quaternion;
+     154             : 
+     155        5001 :   validateOrientation();
+     156        5001 : }
+     157             : 
+     158           1 : AttitudeConverter::AttitudeConverter(const tf2::Matrix3x3 matrix) {
+     159             : 
+     160           1 :   matrix.getRotation(tf2_quaternion_);
+     161             : 
+     162           1 :   validateOrientation();
+     163           1 : }
+     164             : 
+     165             : //}
+     166             : 
+     167             : /* operators //{ */
+     168             : 
+     169        2004 : AttitudeConverter::operator tf2::Quaternion() const {
+     170        2004 :   return tf2_quaternion_;
+     171             : }
+     172             : 
+     173           1 : AttitudeConverter::operator tf::Quaternion() const {
+     174             : 
+     175           1 :   tf::Quaternion tf_quaternion;
+     176             : 
+     177           1 :   tf_quaternion.setX(tf2_quaternion_.x());
+     178           1 :   tf_quaternion.setY(tf2_quaternion_.y());
+     179           1 :   tf_quaternion.setZ(tf2_quaternion_.z());
+     180           1 :   tf_quaternion.setW(tf2_quaternion_.w());
+     181             : 
+     182           1 :   return tf_quaternion;
+     183             : }
+     184             : 
+     185           1 : AttitudeConverter::operator geometry_msgs::Quaternion() const {
+     186             : 
+     187           1 :   geometry_msgs::Quaternion geom_quaternion;
+     188             : 
+     189           1 :   geom_quaternion.x = tf2_quaternion_.x();
+     190           1 :   geom_quaternion.y = tf2_quaternion_.y();
+     191           1 :   geom_quaternion.z = tf2_quaternion_.z();
+     192           1 :   geom_quaternion.w = tf2_quaternion_.w();
+     193             : 
+     194           1 :   return geom_quaternion;
+     195             : }
+     196             : 
+     197           1 : AttitudeConverter::operator EulerAttitude() const {
+     198             : 
+     199             :   double roll, pitch, yaw;
+     200           1 :   tf2::Matrix3x3(tf2_quaternion_).getRPY(roll, pitch, yaw);
+     201             : 
+     202           2 :   return EulerAttitude(roll, pitch, yaw);
+     203             : }
+     204             : 
+     205         133 : AttitudeConverter::operator Eigen::Matrix3d() const {
+     206             : 
+     207         133 :   Eigen::Quaterniond quaternion(tf2_quaternion_.w(), tf2_quaternion_.x(), tf2_quaternion_.y(), tf2_quaternion_.z());
+     208             : 
+     209         266 :   return quaternion.toRotationMatrix();
+     210             : }
+     211             : 
+     212           1 : AttitudeConverter::operator std::tuple<double&, double&, double&>() {
+     213             : 
+     214           1 :   tf2::Matrix3x3(tf2_quaternion_).getRPY(roll_, pitch_, yaw_);
+     215             : 
+     216           1 :   return std::tuple<double&, double&, double&>{roll_, pitch_, yaw_};
+     217             : }
+     218             : 
+     219           1 : AttitudeConverter::operator tf2::Matrix3x3() const {
+     220             : 
+     221           1 :   return tf2::Matrix3x3(tf2_quaternion_);
+     222             : }
+     223             : 
+     224           0 : AttitudeConverter::operator tf2::Transform() const {
+     225             : 
+     226           0 :   return tf2::Transform(tf2_quaternion_);
+     227             : }
+     228             : 
+     229             : //}
+     230             : 
+     231             : /* getters //{ */
+     232             : 
+     233           1 : double AttitudeConverter::getYaw(void) {
+     234             : 
+     235           1 :   calculateRPY();
+     236             : 
+     237           1 :   return yaw_;
+     238             : }
+     239             : 
+     240           1 : double AttitudeConverter::getRoll(void) {
+     241             : 
+     242           1 :   calculateRPY();
+     243             : 
+     244           1 :   return roll_;
+     245             : }
+     246             : 
+     247           1 : double AttitudeConverter::getPitch(void) {
+     248             : 
+     249           1 :   calculateRPY();
+     250             : 
+     251           1 :   return pitch_;
+     252             : }
+     253             : 
+     254        2062 : double AttitudeConverter::getHeading(void) {
+     255             : 
+     256        2062 :   tf2::Vector3 b1 = tf2::Vector3(1, 0, 0);
+     257             : 
+     258        2062 :   tf2::Vector3 x_new = tf2::Transform(tf2_quaternion_) * b1;
+     259             : 
+     260        2062 :   if (fabs(x_new[0]) <= 1e-3 && fabs(x_new[1]) <= 1e-3) {
+     261           1 :     throw GetHeadingException();
+     262             :   }
+     263             : 
+     264        4122 :   return atan2(x_new[1], x_new[0]);
+     265             : }
+     266             : 
+     267          63 : double AttitudeConverter::getYawRateIntrinsic(const double& heading_rate) {
+     268             : 
+     269             :   // when the heading rate is very small, it does not make sense to compute the
+     270             :   // yaw rate (the math would break), return 0
+     271          63 :   if (fabs(heading_rate) < 1e-3) {
+     272           0 :     return 0;
+     273             :   }
+     274             : 
+     275             :   // prep
+     276          63 :   Eigen::Matrix3d R = *this;
+     277             : 
+     278             :   // construct the heading orbital velocity vector
+     279          63 :   Eigen::Vector3d heading_vector   = Eigen::Vector3d(R(0, 0), R(1, 0), 0);
+     280          63 :   Eigen::Vector3d orbital_velocity = Eigen::Vector3d(0, 0, heading_rate).cross(heading_vector);
+     281             : 
+     282             :   // projector to the heading orbital velocity vector subspace
+     283          63 :   Eigen::Vector3d b_orb = Eigen::Vector3d(0, 0, 1).cross(heading_vector);
+     284          63 :   b_orb.normalize();
+     285          63 :   Eigen::Matrix3d P = b_orb * b_orb.transpose();
+     286             : 
+     287             :   // project the body yaw orbital velocity vector base onto the heading orbital velocity vector subspace
+     288          63 :   Eigen::Vector3d projected = P * R.col(1);
+     289             : 
+     290             : 
+     291          63 :   double orbital_velocity_norm = orbital_velocity.norm();
+     292          63 :   double projected_norm        = projected.norm();
+     293             : 
+     294          63 :   if (fabs(projected_norm) < 1e-5) {
+     295           0 :     ROS_ERROR("[AttitudeConverter]: getYawRateIntrinsic(): \"projected_norm\" in denominator is almost zero!!!");
+     296           0 :     throw MathErrorException();
+     297             :   }
+     298             : 
+     299          63 :   double direction = mrs_lib::signum(orbital_velocity.dot(projected));
+     300             : 
+     301          63 :   double output_yaw_rate = direction * (orbital_velocity_norm / projected_norm);
+     302             : 
+     303          63 :   if (!std::isfinite(output_yaw_rate)) {
+     304           0 :     ROS_ERROR("[AttitudeConverter]: getYawRateIntrinsic(): NaN detected in variable \"output_yaw_rate\"!!!");
+     305           0 :     throw MathErrorException();
+     306             :   }
+     307             : 
+     308             :   // extract the yaw rate
+     309          63 :   return output_yaw_rate;
+     310             : }
+     311             : 
+     312          63 : double AttitudeConverter::getHeadingRate(const Vector3Converter& attitude_rate) {
+     313             : 
+     314             :   // prep
+     315          63 :   Eigen::Matrix3d R = *this;
+     316          63 :   Eigen::Vector3d w = attitude_rate;
+     317             : 
+     318             :   // create the angular velocity tensor
+     319          63 :   Eigen::Matrix3d W;
+     320          63 :   W << 0, -w[2], w[1], w[2], 0, -w[0], -w[1], w[0], 0;
+     321             : 
+     322             :   // R derivative
+     323          63 :   Eigen::Matrix3d R_d = R * W;
+     324             : 
+     325             :   // atan2 derivative
+     326          63 :   double rx = R(0, 0);  // x-component of body X
+     327          63 :   double ry = R(1, 0);  // y-component of body Y
+     328             : 
+     329          63 :   double denom = rx * rx + ry * ry;
+     330             : 
+     331          63 :   if (fabs(denom) <= 1e-5) {
+     332           0 :     ROS_ERROR("[AttitudeConverter]: getHeadingRate(): denominator near zero!!!");
+     333           0 :     throw MathErrorException();
+     334             :   }
+     335             : 
+     336          63 :   double atan2_d_x = -ry / denom;
+     337          63 :   double atan2_d_y = rx / denom;
+     338             : 
+     339             :   // atan2 total differential
+     340          63 :   double heading_rate = atan2_d_x * R_d(0, 0) + atan2_d_y * R_d(1, 0);
+     341             : 
+     342          63 :   return heading_rate;
+     343             : }
+     344             : 
+     345           3 : Vector3Converter AttitudeConverter::getVectorX(void) {
+     346             : 
+     347           3 :   tf2::Vector3 b1 = tf2::Vector3(1, 0, 0);
+     348             : 
+     349           3 :   tf2::Vector3 new_b1 = tf2::Transform(tf2_quaternion_) * b1;
+     350             : 
+     351           6 :   return Vector3Converter(new_b1);
+     352             : }
+     353             : 
+     354           3 : Vector3Converter AttitudeConverter::getVectorY(void) {
+     355             : 
+     356           3 :   tf2::Vector3 b2 = tf2::Vector3(0, 1, 0);
+     357             : 
+     358           3 :   tf2::Vector3 new_b2 = tf2::Transform(tf2_quaternion_) * b2;
+     359             : 
+     360           6 :   return Vector3Converter(new_b2);
+     361             : }
+     362             : 
+     363        3001 : Vector3Converter AttitudeConverter::getVectorZ(void) {
+     364             : 
+     365        3001 :   tf2::Vector3 b3 = tf2::Vector3(0, 0, 1);
+     366             : 
+     367        3001 :   tf2::Vector3 new_b3 = tf2::Transform(tf2_quaternion_) * b3;
+     368             : 
+     369        6002 :   return Vector3Converter(new_b3);
+     370             : }
+     371             : 
+     372           1 : std::tuple<double, double, double> AttitudeConverter::getExtrinsicRPY(void) {
+     373             : 
+     374           1 :   Eigen::Matrix3d rot = AttitudeConverter(*this);
+     375             : 
+     376           1 :   Eigen::Vector3d eulers = rot.eulerAngles(2, 1, 0);
+     377             : 
+     378           2 :   return std::tuple(eulers[2], eulers[1], eulers[0]);
+     379             : }
+     380             : 
+     381           1 : std::tuple<double, double, double> AttitudeConverter::getIntrinsicRPY(void) {
+     382             : 
+     383           1 :   Eigen::Matrix3d rot = AttitudeConverter(*this);
+     384             : 
+     385           1 :   Eigen::Vector3d eulers = rot.eulerAngles(0, 1, 2);
+     386             : 
+     387           2 :   return std::tuple(eulers[0], eulers[1], eulers[2]);
+     388             : }
+     389             : 
+     390             : //}
+     391             : 
+     392             : /* setters //{ */
+     393             : 
+     394           0 : AttitudeConverter AttitudeConverter::setYaw(const double& new_yaw) {
+     395             : 
+     396           0 :   auto [roll, pitch, yaw] = *this;
+     397             : 
+     398           0 :   std::ignore = yaw;
+     399             : 
+     400           0 :   return AttitudeConverter(roll, pitch, new_yaw);
+     401             : }
+     402             : 
+     403        1000 : AttitudeConverter AttitudeConverter::setHeading(const double& heading) {
+     404             : 
+     405             :   // get the Z unit vector after the original rotation
+     406        1000 :   Eigen::Vector3d b3 = getVectorZ();
+     407             : 
+     408             :   // check for singularity: z component of the thrust vector is 0
+     409        1000 :   if (fabs(b3[2]) < 1e-3) {
+     410           4 :     throw SetHeadingException();
+     411             :   }
+     412             : 
+     413             :   // get the desired heading as a vector in 3D
+     414         996 :   Eigen::Vector3d h(cos(heading), sin(heading), 0);
+     415             : 
+     416         996 :   Eigen::Matrix3d new_R;
+     417             : 
+     418         996 :   new_R.col(2) = b3;
+     419             : 
+     420             :   // construct the oblique projection
+     421         996 :   Eigen::Matrix3d projector_body_z_compl = (Eigen::Matrix3d::Identity(3, 3) - b3 * b3.transpose());
+     422             : 
+     423             :   // create a basis of the body-z complement subspace
+     424        1992 :   Eigen::MatrixXd A = Eigen::MatrixXd(3, 2);
+     425         996 :   A.col(0)          = projector_body_z_compl.col(0);
+     426         996 :   A.col(1)          = projector_body_z_compl.col(1);
+     427             : 
+     428             :   // create the basis of the projection null-space complement
+     429        1992 :   Eigen::MatrixXd B = Eigen::MatrixXd(3, 2);
+     430         996 :   B.col(0)          = Eigen::Vector3d(1, 0, 0);
+     431         996 :   B.col(1)          = Eigen::Vector3d(0, 1, 0);
+     432             : 
+     433             :   // oblique projector to <range_basis>
+     434        1992 :   Eigen::MatrixXd Bt_A               = B.transpose() * A;
+     435        1992 :   Eigen::MatrixXd Bt_A_pseudoinverse = ((Bt_A.transpose() * Bt_A).inverse()) * Bt_A.transpose();
+     436         996 :   Eigen::MatrixXd oblique_projector  = A * Bt_A_pseudoinverse * B.transpose();
+     437             : 
+     438         996 :   new_R.col(0) = oblique_projector * h;
+     439         996 :   new_R.col(0).normalize();
+     440             : 
+     441             :   // | ------------------------- body y ------------------------- |
+     442             : 
+     443         996 :   new_R.col(1) = new_R.col(2).cross(new_R.col(0));
+     444         996 :   new_R.col(1).normalize();
+     445             : 
+     446        1992 :   return AttitudeConverter(new_R);
+     447             : }
+     448             : 
+     449             : //}
+     450             : 
+     451             : // | ------------------------ internal ------------------------ |
+     452             : 
+     453             : /* calculateRPY() //{ */
+     454             : 
+     455           6 : void AttitudeConverter::calculateRPY(void) {
+     456             : 
+     457           6 :   if (!got_rpy_) {
+     458             : 
+     459           6 :     tf2::Matrix3x3(tf2_quaternion_).getRPY(roll_, pitch_, yaw_);
+     460             :   }
+     461           6 : }
+     462             : 
+     463             : //}
+     464             : 
+     465             : /* validateOrientation() //{ */
+     466             : 
+     467        7218 : void AttitudeConverter::validateOrientation(void) {
+     468             : 
+     469       14434 :   if (!std::isfinite(tf2_quaternion_.x()) || !std::isfinite(tf2_quaternion_.y()) || !std::isfinite(tf2_quaternion_.z()) ||
+     470        7216 :       !std::isfinite(tf2_quaternion_.w())) {
+     471           2 :     throw InvalidAttitudeException();
+     472             :   }
+     473        7216 : }
+     474             : 
+     475             : //}
+     476             : 
+     477             : }  // namespace mrs_lib
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/attitude_converter/index-sort-f.html b/mrs_lib/src/attitude_converter/index-sort-f.html new file mode 100644 index 0000000000..08d21c0dd4 --- /dev/null +++ b/mrs_lib/src/attitude_converter/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/attitude_converter + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/attitude_converterHitTotalCoverage
Test:coverage.infoLines:20422491.1 %
Date:2023-11-29 14:09:54Functions:374190.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
attitude_converter.cpp +
91.1%91.1%
+
91.1 %204 / 22490.2 %37 / 41
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/attitude_converter/index-sort-l.html b/mrs_lib/src/attitude_converter/index-sort-l.html new file mode 100644 index 0000000000..b77158683c --- /dev/null +++ b/mrs_lib/src/attitude_converter/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/attitude_converter + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/attitude_converterHitTotalCoverage
Test:coverage.infoLines:20422491.1 %
Date:2023-11-29 14:09:54Functions:374190.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
attitude_converter.cpp +
91.1%91.1%
+
91.1 %204 / 22490.2 %37 / 41
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/attitude_converter/index.html b/mrs_lib/src/attitude_converter/index.html new file mode 100644 index 0000000000..27f3b660ba --- /dev/null +++ b/mrs_lib/src/attitude_converter/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/attitude_converter + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/attitude_converterHitTotalCoverage
Test:coverage.infoLines:20422491.1 %
Date:2023-11-29 14:09:54Functions:374190.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
attitude_converter.cpp +
91.1%91.1%
+
91.1 %204 / 22490.2 %37 / 41
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/conversions.cpp.func-sort-c.html b/mrs_lib/src/geometry/conversions.cpp.func-sort-c.html new file mode 100644 index 0000000000..c8ac3bf04d --- /dev/null +++ b/mrs_lib/src/geometry/conversions.cpp.func-sort-c.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/conversions.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - conversions.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:324669.6 %
Date:2023-11-29 14:09:54Functions:71070.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry13toEigenMatrixERKN5boost5arrayIdLm36EEE0
_ZN7mrs_lib8geometry4toCVERKN13geometry_msgs8Vector3_ISaIvEEE0
_ZN7mrs_lib8geometry9fromEigenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZN7mrs_lib8geometry4toCVERKN13geometry_msgs6Point_ISaIvEEE1
_ZN7mrs_lib8geometry6fromCVERKN2cv7Point3_IdEE1
_ZN7mrs_lib8geometry7toEigenERKN13geometry_msgs11Quaternion_ISaIvEEE6
_ZN7mrs_lib8geometry9fromEigenERKN5Eigen10QuaternionIdLi0EEE6
_ZN7mrs_lib8geometry7toEigenERKN13geometry_msgs8Vector3_ISaIvEEE19
_ZN7mrs_lib8geometry12fromEigenVecERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE22
_ZN7mrs_lib8geometry7toEigenERKN13geometry_msgs6Point_ISaIvEEE28
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/conversions.cpp.func.html b/mrs_lib/src/geometry/conversions.cpp.func.html new file mode 100644 index 0000000000..86388b5434 --- /dev/null +++ b/mrs_lib/src/geometry/conversions.cpp.func.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/conversions.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - conversions.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:324669.6 %
Date:2023-11-29 14:09:54Functions:71070.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry12fromEigenVecERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE22
_ZN7mrs_lib8geometry13toEigenMatrixERKN5boost5arrayIdLm36EEE0
_ZN7mrs_lib8geometry4toCVERKN13geometry_msgs6Point_ISaIvEEE1
_ZN7mrs_lib8geometry4toCVERKN13geometry_msgs8Vector3_ISaIvEEE0
_ZN7mrs_lib8geometry6fromCVERKN2cv7Point3_IdEE1
_ZN7mrs_lib8geometry7toEigenERKN13geometry_msgs11Quaternion_ISaIvEEE6
_ZN7mrs_lib8geometry7toEigenERKN13geometry_msgs6Point_ISaIvEEE28
_ZN7mrs_lib8geometry7toEigenERKN13geometry_msgs8Vector3_ISaIvEEE19
_ZN7mrs_lib8geometry9fromEigenERKN5Eigen10QuaternionIdLi0EEE6
_ZN7mrs_lib8geometry9fromEigenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/conversions.cpp.gcov.html b/mrs_lib/src/geometry/conversions.cpp.gcov.html new file mode 100644 index 0000000000..417619476f --- /dev/null +++ b/mrs_lib/src/geometry/conversions.cpp.gcov.html @@ -0,0 +1,170 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/conversions.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - conversions.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:324669.6 %
Date:2023-11-29 14:09:54Functions:71070.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_lib/geometry/conversions.h>
+       2             : 
+       3             : namespace mrs_lib
+       4             : {
+       5             :   namespace geometry
+       6             :   {
+       7             : 
+       8             :     /* conversions from/to Eigen //{ */
+       9             :     
+      10           0 :     geometry_msgs::Point fromEigen(const Eigen::Vector3d& what)
+      11             :     {
+      12           0 :       geometry_msgs::Point pt;
+      13           0 :       pt.x = what.x();
+      14           0 :       pt.y = what.y();
+      15           0 :       pt.z = what.z();
+      16           0 :       return pt;
+      17             :     }
+      18             :     
+      19          22 :     geometry_msgs::Vector3 fromEigenVec(const Eigen::Vector3d& what)
+      20             :     {
+      21          22 :       geometry_msgs::Vector3 pt;
+      22          22 :       pt.x = what.x();
+      23          22 :       pt.y = what.y();
+      24          22 :       pt.z = what.z();
+      25          22 :       return pt;
+      26             :     }
+      27             :     
+      28          28 :     Eigen::Vector3d toEigen(const geometry_msgs::Point& what)
+      29             :     {
+      30          28 :       return {what.x, what.y, what.z};
+      31             :     }
+      32             :     
+      33          19 :     Eigen::Vector3d toEigen(const geometry_msgs::Vector3& what)
+      34             :     {
+      35          19 :       return {what.x, what.y, what.z};
+      36             :     }
+      37             :     
+      38           0 :     Eigen::Matrix<double, 6, 6> toEigenMatrix(const boost::array<double, 36>& what)
+      39             :     {
+      40           0 :       Eigen::Matrix<double, 6, 6> ret;
+      41           0 :       for (int r = 0; r < 6; r++)
+      42           0 :         for (int c = 0; c < 6; c++)
+      43           0 :           ret(r, c) = what.at(6 * r + c);
+      44           0 :       return ret;
+      45             :     }
+      46             :     
+      47           6 :     geometry_msgs::Quaternion fromEigen(const Eigen::Quaterniond& what)
+      48             :     {
+      49           6 :       geometry_msgs::Quaternion q;
+      50           6 :       q.x = what.x();
+      51           6 :       q.y = what.y();
+      52           6 :       q.z = what.z();
+      53           6 :       q.w = what.w();
+      54           6 :       return q;
+      55             :     }
+      56             :     
+      57           6 :     Eigen::Quaterniond toEigen(const geometry_msgs::Quaternion& what)
+      58             :     {
+      59             :       // better to do this manually than through the constructor to avoid ambiguities (e.g. position of x and w)
+      60           6 :       Eigen::Quaterniond q;
+      61           6 :       q.x() = what.x;
+      62           6 :       q.y() = what.y;
+      63           6 :       q.z() = what.z;
+      64           6 :       q.w() = what.w;
+      65           6 :       return q;
+      66             :     }
+      67             :     
+      68             :     //}
+      69             : 
+      70             :     /* conversions from/to OpenCV //{ */
+      71             :     
+      72           1 :     geometry_msgs::Point fromCV(const cv::Point3d& what)
+      73             :     {
+      74           1 :       geometry_msgs::Point pt;
+      75           1 :       pt.x = what.x;
+      76           1 :       pt.y = what.y;
+      77           1 :       pt.z = what.z;
+      78           1 :       return pt;
+      79             :     }
+      80             :     
+      81           1 :     cv::Point3d toCV(const geometry_msgs::Point& what)
+      82             :     {
+      83           1 :       return {what.x, what.y, what.z};
+      84             :     }
+      85             :     
+      86           0 :     cv::Point3d toCV(const geometry_msgs::Vector3& what)
+      87             :     {
+      88           0 :       return {what.x, what.y, what.z};
+      89             :     }
+      90             :     
+      91             :     //}
+      92             : 
+      93             :   }
+      94             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/index-sort-f.html b/mrs_lib/src/geometry/index-sort-f.html new file mode 100644 index 0000000000..3562f47753 --- /dev/null +++ b/mrs_lib/src/geometry/index-sort-f.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometryHitTotalCoverage
Test:coverage.infoLines:6344514.2 %
Date:2023-11-29 14:09:54Functions:139413.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
shapes.cpp +
0.0%
+
0.0 %0 / 3350.0 %0 / 68
misc.cpp +
48.4%48.4%
+
48.4 %31 / 6437.5 %6 / 16
conversions.cpp +
69.6%69.6%
+
69.6 %32 / 4670.0 %7 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/index-sort-l.html b/mrs_lib/src/geometry/index-sort-l.html new file mode 100644 index 0000000000..ca5afa3010 --- /dev/null +++ b/mrs_lib/src/geometry/index-sort-l.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometryHitTotalCoverage
Test:coverage.infoLines:6344514.2 %
Date:2023-11-29 14:09:54Functions:139413.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
shapes.cpp +
0.0%
+
0.0 %0 / 3350.0 %0 / 68
misc.cpp +
48.4%48.4%
+
48.4 %31 / 6437.5 %6 / 16
conversions.cpp +
69.6%69.6%
+
69.6 %32 / 4670.0 %7 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/index.html b/mrs_lib/src/geometry/index.html new file mode 100644 index 0000000000..73ef27e8b5 --- /dev/null +++ b/mrs_lib/src/geometry/index.html @@ -0,0 +1,113 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometryHitTotalCoverage
Test:coverage.infoLines:6344514.2 %
Date:2023-11-29 14:09:54Functions:139413.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
conversions.cpp +
69.6%69.6%
+
69.6 %32 / 4670.0 %7 / 10
misc.cpp +
48.4%48.4%
+
48.4 %31 / 6437.5 %6 / 16
shapes.cpp +
0.0%
+
0.0 %0 / 3350.0 %0 / 68
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/misc.cpp.func-sort-c.html b/mrs_lib/src/geometry/misc.cpp.func-sort-c.html new file mode 100644 index 0000000000..55de03bced --- /dev/null +++ b/mrs_lib/src/geometry/misc.cpp.func-sort-c.html @@ -0,0 +1,136 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/misc.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - misc.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:316448.4 %
Date:2023-11-29 14:09:54Functions:61637.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry10solidAngleEddd0
_ZN7mrs_lib8geometry11invHaversinEd0
_ZN7mrs_lib8geometry12triangleAreaEddd0
_ZN7mrs_lib8geometry17quaternionBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_d0
_ZN7mrs_lib8geometry19quaternionFromEulerERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZN7mrs_lib8geometry19quaternionFromEulerEddd0
_ZN7mrs_lib8geometry21sphericalTriangleAreaEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES3_S3_0
_ZN7mrs_lib8geometry4distERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEES5_0
_ZN7mrs_lib8geometry4distERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_0
_ZN7mrs_lib8geometry8haversinEd0
_ZN7mrs_lib8geometry12angleBetweenERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEES5_3
_ZN7mrs_lib8geometry12angleBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_3
_ZN7mrs_lib8geometry15rotationBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_d3
_ZN7mrs_lib8geometry16angleaxisBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_d3
_ZN7mrs_lib8geometry5crossERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEES3_3
_ZN7mrs_lib8geometry21quaternionFromHeadingEd12
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/misc.cpp.func.html b/mrs_lib/src/geometry/misc.cpp.func.html new file mode 100644 index 0000000000..64a664649b --- /dev/null +++ b/mrs_lib/src/geometry/misc.cpp.func.html @@ -0,0 +1,136 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/misc.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - misc.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:316448.4 %
Date:2023-11-29 14:09:54Functions:61637.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry10solidAngleEddd0
_ZN7mrs_lib8geometry11invHaversinEd0
_ZN7mrs_lib8geometry12angleBetweenERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEES5_3
_ZN7mrs_lib8geometry12angleBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_3
_ZN7mrs_lib8geometry12triangleAreaEddd0
_ZN7mrs_lib8geometry15rotationBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_d3
_ZN7mrs_lib8geometry16angleaxisBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_d3
_ZN7mrs_lib8geometry17quaternionBetweenERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_d0
_ZN7mrs_lib8geometry19quaternionFromEulerERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZN7mrs_lib8geometry19quaternionFromEulerEddd0
_ZN7mrs_lib8geometry21quaternionFromHeadingEd12
_ZN7mrs_lib8geometry21sphericalTriangleAreaEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES3_S3_0
_ZN7mrs_lib8geometry4distERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEES5_0
_ZN7mrs_lib8geometry4distERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES5_0
_ZN7mrs_lib8geometry5crossERKN5Eigen6MatrixIdLi2ELi1ELi0ELi2ELi1EEES3_3
_ZN7mrs_lib8geometry8haversinEd0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/misc.cpp.gcov.html b/mrs_lib/src/geometry/misc.cpp.gcov.html new file mode 100644 index 0000000000..b70a43541f --- /dev/null +++ b/mrs_lib/src/geometry/misc.cpp.gcov.html @@ -0,0 +1,261 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/misc.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - misc.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:316448.4 %
Date:2023-11-29 14:09:54Functions:61637.5 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : #include <mrs_lib/geometry/misc.h>
+       3             : 
+       4             : namespace mrs_lib
+       5             : {
+       6             :   namespace geometry
+       7             :   {
+       8             : 
+       9             :     // instantiation of common template values
+      10             :     vec_t<3 + 1> toHomogenous(const vec_t<3>& vec);
+      11             :     vec_t<2 + 1> toHomogenous(const vec_t<2>& vec);
+      12             : 
+      13             :     // | ----------------- Angle-related functions ---------------- |
+      14             : 
+      15             :     /* angle-related functions //{ */
+      16             : 
+      17             :     /* cross() //{ */
+      18             : 
+      19           3 :     double cross(const vec2_t& vec1, const vec2_t vec2)
+      20             :     {
+      21           3 :       return vec1.x() * vec2.y() - vec1.y() * vec2.x();
+      22             :     }
+      23             : 
+      24             :     //}
+      25             : 
+      26             :     /* angleBetween() //{ */
+      27             : 
+      28           3 :     double angleBetween(const vec3_t& vec1, const vec3_t& vec2)
+      29             :     {
+      30           3 :       const double sin_12 = vec1.cross(vec2).norm();
+      31           3 :       const double cos_12 = vec1.dot(vec2);
+      32           3 :       const double angle = std::atan2(sin_12, cos_12);
+      33           3 :       return angle;
+      34             :     }
+      35             : 
+      36           3 :     double angleBetween(const vec2_t& vec1, const vec2_t& vec2)
+      37             :     {
+      38           3 :       const double sin_12 = cross(vec1, vec2);
+      39           3 :       const double cos_12 = vec1.dot(vec2);
+      40           3 :       const double angle = std::atan2(sin_12, cos_12);
+      41           3 :       return angle;
+      42             :     }
+      43             : 
+      44             :     //}
+      45             : 
+      46             :     /* angleaxisBetween() //{ */
+      47             : 
+      48           3 :     anax_t angleaxisBetween(const Eigen::Vector3d& vec1, const Eigen::Vector3d& vec2, const double tolerance)
+      49             :     {
+      50             :       // Find the rotation matrix to rotate vec1 to point in the direction of vec2
+      51           3 :       const Eigen::Vector3d a = vec1.normalized();
+      52           3 :       const Eigen::Vector3d b = vec2.normalized();
+      53           3 :       const Eigen::Vector3d v = a.cross(b);
+      54           3 :       const double sin_ab = v.norm();
+      55           3 :       const double cos_ab = a.dot(b);
+      56           3 :       const double angle = std::atan2(sin_ab, cos_ab);
+      57           3 :       anax_t ret;
+      58           3 :       if (abs(angle) < tolerance)
+      59           1 :         ret = anax_t(0.0, Eigen::Vector3d::UnitX());
+      60           2 :       else if (abs(abs(angle) - M_PI) < tolerance)
+      61           0 :         ret = anax_t(M_PI, Eigen::Vector3d::UnitX());
+      62             :       else
+      63           2 :         ret = anax_t(angle, v.normalized());
+      64           6 :       return ret;
+      65             :     }
+      66             : 
+      67             :     //}
+      68             : 
+      69             :     /* quaternionBetween() //{ */
+      70             : 
+      71           0 :     quat_t quaternionBetween(const Eigen::Vector3d& vec1, const Eigen::Vector3d& vec2, const double tolerance)
+      72             :     {
+      73           0 :       const auto rot = angleaxisBetween(vec1, vec2, tolerance);
+      74           0 :       const quat_t ret(rot);
+      75           0 :       return ret;
+      76             :     }
+      77             : 
+      78             :     /* quaternionFromEuler() overloads //{ */
+      79           0 :     quat_t quaternionFromEuler(double x, double y, double z)
+      80             :     {
+      81           0 :       return anax_t(x, vec3_t::UnitX()) * anax_t(y, vec3_t::UnitY()) * anax_t(z, vec3_t::UnitZ());
+      82             :     }
+      83             : 
+      84           0 :     quat_t quaternionFromEuler(const Eigen::Vector3d& euler)
+      85             :     {
+      86           0 :       return anax_t(euler.x(), vec3_t::UnitX()) * anax_t(euler.y(), vec3_t::UnitY())
+      87           0 :              * anax_t(euler.z(), vec3_t::UnitZ());
+      88             :     }
+      89             :     //}
+      90             : 
+      91             :     /* quaternionFromHeading //{ */
+      92          12 :     quat_t quaternionFromHeading(const double heading)
+      93             :     {
+      94          24 :       return quat_t(anax_t(heading, Eigen::Vector3d::UnitZ()));
+      95             :     }
+      96             :     //}
+      97             : 
+      98             :     //}
+      99             : 
+     100             :     /* rotationBetween() //{ */
+     101             : 
+     102           3 :     Eigen::Matrix3d rotationBetween(const Eigen::Vector3d& vec1, const Eigen::Vector3d& vec2, const double tolerance)
+     103             :     {
+     104           3 :       const auto rot = angleaxisBetween(vec1, vec2, tolerance);
+     105           3 :       const Eigen::Matrix3d ret(rot);
+     106           6 :       return ret;
+     107             :     }
+     108             : 
+     109             :     //}
+     110             : 
+     111             :     /* haversin() //{ */
+     112             : 
+     113           0 :     double haversin(const double angle)
+     114             :     {
+     115           0 :       return (1.0 - std::cos(angle)) / 2.0;
+     116             :     }
+     117             : 
+     118             :     //}
+     119             : 
+     120             :     /* invHaversin() //{ */
+     121             : 
+     122           0 :     double invHaversin(const double value)
+     123             :     {
+     124           0 :       return 2.0 * std::asin(std::sqrt(value));
+     125             :     }
+     126             : 
+     127             :     //}
+     128             : 
+     129             :     /* solidAngle() //{ */
+     130           0 :     double solidAngle(double a, double b, double c)
+     131             :     {
+     132           0 :       return invHaversin((haversin(c) - haversin(a - b)) / (std::sin(a) * std::sin(b)));
+     133             :     }
+     134             :     //}
+     135             : 
+     136             :     //}
+     137             : 
+     138             :     /* triangleArea() //{ */
+     139             : 
+     140           0 :     double triangleArea(const double a, const double b, const double c)
+     141             :     {
+     142           0 :       double s = (a + b + c) / 2.0;
+     143           0 :       return std::sqrt(s * (s - a) * (s - b) * (s - c));
+     144             :     }
+     145             : 
+     146             :     //}
+     147             : 
+     148             :     /* sphericalTriangleArea //{ */
+     149           0 :     double sphericalTriangleArea(Eigen::Vector3d a, Eigen::Vector3d b, Eigen::Vector3d c)
+     150             :     {
+     151           0 :       double ab = angleBetween(a, b);
+     152           0 :       double bc = angleBetween(b, c);
+     153           0 :       double ca = angleBetween(c, a);
+     154             : 
+     155           0 :       if (ab < 1e-3 and bc < 1e-3 and ca < 1e-3)
+     156             :       {
+     157           0 :         return triangleArea(ab, bc, ca);
+     158             :       }
+     159             : 
+     160           0 :       double A = solidAngle(ca, ab, bc);
+     161           0 :       double B = solidAngle(ab, bc, ca);
+     162           0 :       double C = solidAngle(bc, ca, ab);
+     163             : 
+     164           0 :       return A + B + C - M_PI;
+     165             :     }
+     166             :     //}
+     167             : 
+     168             :     /* vector distance //{ */
+     169             : 
+     170           0 :     double dist(const vec2_t& a, const vec2_t& b)
+     171             :     {
+     172             : 
+     173           0 :       return (a - b).norm();
+     174             :     }
+     175             : 
+     176           0 :     double dist(const vec3_t& a, const vec3_t& b)
+     177             :     {
+     178             : 
+     179           0 :       return (a - b).norm();
+     180             :     }
+     181             : 
+     182             :     //}
+     183             : 
+     184             :   }  // namespace geometry
+     185             : }  // namespace mrs_lib
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/shapes.cpp.func-sort-c.html b/mrs_lib/src/geometry/shapes.cpp.func-sort-c.html new file mode 100644 index 0000000000..479d8e91a8 --- /dev/null +++ b/mrs_lib/src/geometry/shapes.cpp.func-sort-c.html @@ -0,0 +1,344 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/shapes.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - shapes.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:03350.0 %
Date:2023-11-29 14:09:54Functions:0680.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry3Ray12twopointCastEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_0
_ZN7mrs_lib8geometry3Ray13directionCastEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_0
_ZN7mrs_lib8geometry3RayC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_0
_ZN7mrs_lib8geometry3RayC2Ev0
_ZN7mrs_lib8geometry3RayD2Ev0
_ZN7mrs_lib8geometry4ConeC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEddS4_0
_ZN7mrs_lib8geometry4ConeC2Ev0
_ZN7mrs_lib8geometry4ConeD2Ev0
_ZN7mrs_lib8geometry6CuboidC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_NS2_10QuaternionIdLi0EEE0
_ZN7mrs_lib8geometry6CuboidC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_S4_S4_S4_S4_S4_S4_0
_ZN7mrs_lib8geometry6CuboidC2ESt6vectorIN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEESaIS5_EE0
_ZN7mrs_lib8geometry6CuboidC2Ev0
_ZN7mrs_lib8geometry6CuboidD2Ev0
_ZN7mrs_lib8geometry7EllipseC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEENS2_10QuaternionIdLi0EEEdd0
_ZN7mrs_lib8geometry7EllipseC2Ev0
_ZN7mrs_lib8geometry7EllipseD2Ev0
_ZN7mrs_lib8geometry8CylinderC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEddNS2_10QuaternionIdLi0EEE0
_ZN7mrs_lib8geometry8CylinderC2Ev0
_ZN7mrs_lib8geometry8CylinderD2Ev0
_ZN7mrs_lib8geometry8TriangleC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_S4_0
_ZN7mrs_lib8geometry8TriangleC2Ev0
_ZN7mrs_lib8geometry8TriangleD2Ev0
_ZN7mrs_lib8geometry9RectangleC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_S4_S4_0
_ZN7mrs_lib8geometry9RectangleC2ESt6vectorIN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEESaIS5_EE0
_ZN7mrs_lib8geometry9RectangleC2Ev0
_ZN7mrs_lib8geometry9RectangleD2Ev0
_ZNK7mrs_lib8geometry3Ray2p1Ev0
_ZNK7mrs_lib8geometry3Ray2p2Ev0
_ZNK7mrs_lib8geometry3Ray9directionEv0
_ZNK7mrs_lib8geometry4Cone12projectPointERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZNK7mrs_lib8geometry4Cone1hEv0
_ZNK7mrs_lib8geometry4Cone5thetaEv0
_ZNK7mrs_lib8geometry4Cone6centerEv0
_ZNK7mrs_lib8geometry4Cone6getCapEv0
_ZNK7mrs_lib8geometry4Cone6originEv0
_ZNK7mrs_lib8geometry4Cone9directionEv0
_ZNK7mrs_lib8geometry6Cuboid12getRectangleEi0
_ZNK7mrs_lib8geometry6Cuboid12lookupPointsEi0
_ZNK7mrs_lib8geometry6Cuboid15intersectionRayENS0_3RayEd0
_ZNK7mrs_lib8geometry6Cuboid6centerEv0
_ZNK7mrs_lib8geometry6Cuboid8verticesEv0
_ZNK7mrs_lib8geometry7Ellipse11orientationEv0
_ZNK7mrs_lib8geometry7Ellipse1aEv0
_ZNK7mrs_lib8geometry7Ellipse1bEv0
_ZNK7mrs_lib8geometry7Ellipse6centerEv0
_ZNK7mrs_lib8geometry8Cylinder11orientationEv0
_ZNK7mrs_lib8geometry8Cylinder1hEv0
_ZNK7mrs_lib8geometry8Cylinder1rEv0
_ZNK7mrs_lib8geometry8Cylinder6centerEv0
_ZNK7mrs_lib8geometry8Cylinder6getCapEi0
_ZNK7mrs_lib8geometry8Triangle15intersectionRayENS0_3RayEd0
_ZNK7mrs_lib8geometry8Triangle1aEv0
_ZNK7mrs_lib8geometry8Triangle1bEv0
_ZNK7mrs_lib8geometry8Triangle1cEv0
_ZNK7mrs_lib8geometry8Triangle6centerEv0
_ZNK7mrs_lib8geometry8Triangle6normalEv0
_ZNK7mrs_lib8geometry8Triangle8verticesEv0
_ZNK7mrs_lib8geometry9Rectangle15intersectionRayENS0_3RayEd0
_ZNK7mrs_lib8geometry9Rectangle1aEv0
_ZNK7mrs_lib8geometry9Rectangle1bEv0
_ZNK7mrs_lib8geometry9Rectangle1cEv0
_ZNK7mrs_lib8geometry9Rectangle1dEv0
_ZNK7mrs_lib8geometry9Rectangle20solidAngleRelativeToEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZNK7mrs_lib8geometry9Rectangle6centerEv0
_ZNK7mrs_lib8geometry9Rectangle6normalEv0
_ZNK7mrs_lib8geometry9Rectangle8isFacingEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZNK7mrs_lib8geometry9Rectangle8verticesEv0
_ZNK7mrs_lib8geometry9Rectangle9trianglesEv0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/shapes.cpp.func.html b/mrs_lib/src/geometry/shapes.cpp.func.html new file mode 100644 index 0000000000..c98ab1432b --- /dev/null +++ b/mrs_lib/src/geometry/shapes.cpp.func.html @@ -0,0 +1,344 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/shapes.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - shapes.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:03350.0 %
Date:2023-11-29 14:09:54Functions:0680.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib8geometry3Ray12twopointCastEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_0
_ZN7mrs_lib8geometry3Ray13directionCastEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_0
_ZN7mrs_lib8geometry3RayC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_0
_ZN7mrs_lib8geometry3RayC2Ev0
_ZN7mrs_lib8geometry3RayD2Ev0
_ZN7mrs_lib8geometry4ConeC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEddS4_0
_ZN7mrs_lib8geometry4ConeC2Ev0
_ZN7mrs_lib8geometry4ConeD2Ev0
_ZN7mrs_lib8geometry6CuboidC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_NS2_10QuaternionIdLi0EEE0
_ZN7mrs_lib8geometry6CuboidC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_S4_S4_S4_S4_S4_S4_0
_ZN7mrs_lib8geometry6CuboidC2ESt6vectorIN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEESaIS5_EE0
_ZN7mrs_lib8geometry6CuboidC2Ev0
_ZN7mrs_lib8geometry6CuboidD2Ev0
_ZN7mrs_lib8geometry7EllipseC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEENS2_10QuaternionIdLi0EEEdd0
_ZN7mrs_lib8geometry7EllipseC2Ev0
_ZN7mrs_lib8geometry7EllipseD2Ev0
_ZN7mrs_lib8geometry8CylinderC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEEddNS2_10QuaternionIdLi0EEE0
_ZN7mrs_lib8geometry8CylinderC2Ev0
_ZN7mrs_lib8geometry8CylinderD2Ev0
_ZN7mrs_lib8geometry8TriangleC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_S4_0
_ZN7mrs_lib8geometry8TriangleC2Ev0
_ZN7mrs_lib8geometry8TriangleD2Ev0
_ZN7mrs_lib8geometry9RectangleC2EN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES4_S4_S4_0
_ZN7mrs_lib8geometry9RectangleC2ESt6vectorIN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEESaIS5_EE0
_ZN7mrs_lib8geometry9RectangleC2Ev0
_ZN7mrs_lib8geometry9RectangleD2Ev0
_ZNK7mrs_lib8geometry3Ray2p1Ev0
_ZNK7mrs_lib8geometry3Ray2p2Ev0
_ZNK7mrs_lib8geometry3Ray9directionEv0
_ZNK7mrs_lib8geometry4Cone12projectPointERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZNK7mrs_lib8geometry4Cone1hEv0
_ZNK7mrs_lib8geometry4Cone5thetaEv0
_ZNK7mrs_lib8geometry4Cone6centerEv0
_ZNK7mrs_lib8geometry4Cone6getCapEv0
_ZNK7mrs_lib8geometry4Cone6originEv0
_ZNK7mrs_lib8geometry4Cone9directionEv0
_ZNK7mrs_lib8geometry6Cuboid12getRectangleEi0
_ZNK7mrs_lib8geometry6Cuboid12lookupPointsEi0
_ZNK7mrs_lib8geometry6Cuboid15intersectionRayENS0_3RayEd0
_ZNK7mrs_lib8geometry6Cuboid6centerEv0
_ZNK7mrs_lib8geometry6Cuboid8verticesEv0
_ZNK7mrs_lib8geometry7Ellipse11orientationEv0
_ZNK7mrs_lib8geometry7Ellipse1aEv0
_ZNK7mrs_lib8geometry7Ellipse1bEv0
_ZNK7mrs_lib8geometry7Ellipse6centerEv0
_ZNK7mrs_lib8geometry8Cylinder11orientationEv0
_ZNK7mrs_lib8geometry8Cylinder1hEv0
_ZNK7mrs_lib8geometry8Cylinder1rEv0
_ZNK7mrs_lib8geometry8Cylinder6centerEv0
_ZNK7mrs_lib8geometry8Cylinder6getCapEi0
_ZNK7mrs_lib8geometry8Triangle15intersectionRayENS0_3RayEd0
_ZNK7mrs_lib8geometry8Triangle1aEv0
_ZNK7mrs_lib8geometry8Triangle1bEv0
_ZNK7mrs_lib8geometry8Triangle1cEv0
_ZNK7mrs_lib8geometry8Triangle6centerEv0
_ZNK7mrs_lib8geometry8Triangle6normalEv0
_ZNK7mrs_lib8geometry8Triangle8verticesEv0
_ZNK7mrs_lib8geometry9Rectangle15intersectionRayENS0_3RayEd0
_ZNK7mrs_lib8geometry9Rectangle1aEv0
_ZNK7mrs_lib8geometry9Rectangle1bEv0
_ZNK7mrs_lib8geometry9Rectangle1cEv0
_ZNK7mrs_lib8geometry9Rectangle1dEv0
_ZNK7mrs_lib8geometry9Rectangle20solidAngleRelativeToEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZNK7mrs_lib8geometry9Rectangle6centerEv0
_ZNK7mrs_lib8geometry9Rectangle6normalEv0
_ZNK7mrs_lib8geometry9Rectangle8isFacingEN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE0
_ZNK7mrs_lib8geometry9Rectangle8verticesEv0
_ZNK7mrs_lib8geometry9Rectangle9trianglesEv0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/geometry/shapes.cpp.gcov.html b/mrs_lib/src/geometry/shapes.cpp.gcov.html new file mode 100644 index 0000000000..3d20c900aa --- /dev/null +++ b/mrs_lib/src/geometry/shapes.cpp.gcov.html @@ -0,0 +1,722 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/geometry/shapes.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/geometry - shapes.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:03350.0 %
Date:2023-11-29 14:09:54Functions:0680.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : #include <mrs_lib/geometry/shapes.h>
+       3             : #include <mrs_lib/geometry/misc.h>
+       4             : 
+       5             : namespace mrs_lib
+       6             : {
+       7             :   namespace geometry
+       8             :   {
+       9             : 
+      10             :     /* Ray //{ */
+      11             : 
+      12             :     /* constructors //{ */
+      13           0 :     Ray::Ray()
+      14             :     {
+      15           0 :       point1 = Eigen::Vector3d::Zero();
+      16           0 :       point2 = Eigen::Vector3d::Zero();
+      17           0 :     }
+      18             : 
+      19           0 :     Ray::Ray(Eigen::Vector3d p1, Eigen::Vector3d p2)
+      20             :     {
+      21           0 :       point1 = p1;
+      22           0 :       point2 = p2;
+      23           0 :     }
+      24             : 
+      25           0 :     Ray::~Ray()
+      26             :     {
+      27           0 :     }
+      28             :     //}
+      29             : 
+      30             :     /* getters //{ */
+      31           0 :     const Eigen::Vector3d Ray::p1() const
+      32             :     {
+      33           0 :       return point1;
+      34             :     }
+      35             : 
+      36           0 :     const Eigen::Vector3d Ray::p2() const
+      37             :     {
+      38           0 :       return point2;
+      39             :     }
+      40             : 
+      41           0 :     const Eigen::Vector3d Ray::direction() const
+      42             :     {
+      43           0 :       return (point2 - point1);
+      44             :     }
+      45             :     //}
+      46             : 
+      47             :     /* raycasting //{ */
+      48           0 :     Ray Ray::twopointCast(Eigen::Vector3d pointFrom, Eigen::Vector3d pointTo)
+      49             :     {
+      50           0 :       return Ray(pointFrom, pointTo);
+      51             :     }
+      52             : 
+      53           0 :     Ray Ray::directionCast(Eigen::Vector3d origin, Eigen::Vector3d direction)
+      54             :     {
+      55           0 :       return Ray(origin, origin + direction);
+      56             :     }
+      57             :     //}
+      58             : 
+      59             :     //}
+      60             : 
+      61             :     /* Triangle //{ */
+      62             : 
+      63             :     /* constructors //{ */
+      64           0 :     Triangle::Triangle()
+      65             :     {
+      66           0 :       point1 = Eigen::Vector3d(0, 0, 0);
+      67           0 :       point2 = Eigen::Vector3d(1, 0, 0);
+      68           0 :       point3 = Eigen::Vector3d(0, 0, 1);
+      69           0 :     }
+      70             : 
+      71           0 :     Triangle::Triangle(Eigen::Vector3d a, Eigen::Vector3d b, Eigen::Vector3d c)
+      72             :     {
+      73           0 :       point1 = a;
+      74           0 :       point2 = b;
+      75           0 :       point3 = c;
+      76           0 :     }
+      77             : 
+      78           0 :     Triangle::~Triangle()
+      79             :     {
+      80           0 :     }
+      81             :     //}
+      82             : 
+      83             :     /* getters //{ */
+      84           0 :     const Eigen::Vector3d Triangle::a() const
+      85             :     {
+      86           0 :       return point1;
+      87             :     }
+      88             : 
+      89           0 :     const Eigen::Vector3d Triangle::b() const
+      90             :     {
+      91           0 :       return point2;
+      92             :     }
+      93             : 
+      94           0 :     const Eigen::Vector3d Triangle::c() const
+      95             :     {
+      96           0 :       return point3;
+      97             :     }
+      98             : 
+      99           0 :     const Eigen::Vector3d Triangle::normal() const
+     100             :     {
+     101           0 :       Eigen::Vector3d n;
+     102           0 :       n = (point2 - point1).cross(point3 - point1);
+     103           0 :       return n.normalized();
+     104             :     }
+     105             : 
+     106           0 :     const Eigen::Vector3d Triangle::center() const
+     107             :     {
+     108           0 :       return (point1 + point2 + point3) / 3.0;
+     109             :     }
+     110             : 
+     111           0 :     const std::vector<Eigen::Vector3d> Triangle::vertices() const
+     112             :     {
+     113           0 :       std::vector<Eigen::Vector3d> vertices;
+     114           0 :       vertices.push_back(point1);
+     115           0 :       vertices.push_back(point2);
+     116           0 :       vertices.push_back(point3);
+     117           0 :       return vertices;
+     118             :     }
+     119             :     //}
+     120             : 
+     121             :     /* intersectionRay //{ */
+     122           0 :     const boost::optional<Eigen::Vector3d> Triangle::intersectionRay(Ray r, double epsilon) const
+     123             :     {
+     124             :       // The Möller–Trumbore algorithm
+     125             :       // https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
+     126           0 :       Eigen::Vector3d v1 = point2 - point1;
+     127           0 :       Eigen::Vector3d v2 = point3 - point1;
+     128           0 :       Eigen::Vector3d h = r.direction().cross(v2);
+     129           0 :       double res = v1.dot(h);
+     130           0 :       if (res > -epsilon && res < epsilon)
+     131             :       {
+     132           0 :         return boost::none;
+     133             :       }
+     134           0 :       double f = 1.0 / res;
+     135           0 :       Eigen::Vector3d s = r.p1() - point1;
+     136           0 :       double u = f * s.dot(h);
+     137           0 :       if (u < 0.0 || u > 1.0)
+     138             :       {
+     139           0 :         return boost::none;
+     140             :       }
+     141           0 :       Eigen::Vector3d q = s.cross(v1);
+     142           0 :       double v = f * r.direction().dot(q);
+     143           0 :       if (v < 0.0 || u + v > 1.0)
+     144             :       {
+     145           0 :         return boost::none;
+     146             :       }
+     147           0 :       double t = f * v2.dot(q);
+     148           0 :       if (t > epsilon)
+     149             :       {
+     150           0 :         Eigen::Vector3d ret = r.p1() + r.direction() * t;
+     151           0 :         return ret;
+     152             :       }
+     153           0 :       return boost::none;
+     154             :     }
+     155             :     //}
+     156             : 
+     157             :     //}
+     158             : 
+     159             :     /* Rectangle //{ */
+     160             : 
+     161             :     /* constructors //{ */
+     162           0 :     Rectangle::Rectangle()
+     163             :     {
+     164           0 :       point1 = Eigen::Vector3d(0, 0, 0);
+     165           0 :       point2 = Eigen::Vector3d(1, 0, 0);
+     166           0 :       point3 = Eigen::Vector3d(1, 1, 0);
+     167           0 :       point4 = Eigen::Vector3d(0, 1, 0);
+     168           0 :     }
+     169             : 
+     170           0 :     Rectangle::Rectangle(std::vector<Eigen::Vector3d> points)
+     171             :     {
+     172           0 :       point1 = points[0];
+     173           0 :       point2 = points[1];
+     174           0 :       point3 = points[2];
+     175           0 :       point4 = points[3];
+     176           0 :     }
+     177             : 
+     178           0 :     Rectangle::Rectangle(Eigen::Vector3d a, Eigen::Vector3d b, Eigen::Vector3d c, Eigen::Vector3d d)
+     179             :     {
+     180           0 :       point1 = a;
+     181           0 :       point2 = b;
+     182           0 :       point3 = c;
+     183           0 :       point4 = d;
+     184           0 :     }
+     185             : 
+     186           0 :     Rectangle::~Rectangle()
+     187             :     {
+     188           0 :     }
+     189             :     //}
+     190             : 
+     191             :     /* getters //{ */
+     192           0 :     const Eigen::Vector3d Rectangle::a() const
+     193             :     {
+     194           0 :       return point1;
+     195             :     }
+     196             : 
+     197           0 :     const Eigen::Vector3d Rectangle::b() const
+     198             :     {
+     199           0 :       return point2;
+     200             :     }
+     201             : 
+     202           0 :     const Eigen::Vector3d Rectangle::c() const
+     203             :     {
+     204           0 :       return point3;
+     205             :     }
+     206             : 
+     207           0 :     const Eigen::Vector3d Rectangle::d() const
+     208             :     {
+     209           0 :       return point4;
+     210             :     }
+     211             : 
+     212           0 :     const Eigen::Vector3d Rectangle::center() const
+     213             :     {
+     214           0 :       return (point1 + point2 + point3 + point4) / 4.0;
+     215             :     }
+     216             : 
+     217           0 :     const Eigen::Vector3d Rectangle::normal() const
+     218             :     {
+     219           0 :       Eigen::Vector3d n;
+     220           0 :       n = (point2 - point1).cross(point4 - point1);
+     221           0 :       return n.normalized();
+     222             :     }
+     223             : 
+     224           0 :     const std::vector<Eigen::Vector3d> Rectangle::vertices() const
+     225             :     {
+     226           0 :       std::vector<Eigen::Vector3d> vertices;
+     227           0 :       vertices.push_back(point1);
+     228           0 :       vertices.push_back(point2);
+     229           0 :       vertices.push_back(point3);
+     230           0 :       vertices.push_back(point4);
+     231           0 :       return vertices;
+     232             :     }
+     233             : 
+     234           0 :     const std::vector<Triangle> Rectangle::triangles() const
+     235             :     {
+     236           0 :       Triangle t1(point1, point2, point3);
+     237           0 :       Triangle t2(point1, point3, point4);
+     238             : 
+     239           0 :       std::vector<Triangle> triangles;
+     240           0 :       triangles.push_back(t1);
+     241           0 :       triangles.push_back(t2);
+     242           0 :       return triangles;
+     243             :     }
+     244             :     //}
+     245             : 
+     246             :     /* intersectionRay //{ */
+     247           0 :     const boost::optional<Eigen::Vector3d> Rectangle::intersectionRay(Ray r, double epsilon) const
+     248             :     {
+     249           0 :       Triangle t1 = triangles()[0];
+     250           0 :       Triangle t2 = triangles()[1];
+     251           0 :       auto result = t1.intersectionRay(r, epsilon);
+     252           0 :       if (result != boost::none)
+     253             :       {
+     254           0 :         return result;
+     255             :       }
+     256           0 :       return t2.intersectionRay(r, epsilon);
+     257             :     }
+     258             :     //}
+     259             : 
+     260             :     /* isFacing //{ */
+     261           0 :     bool Rectangle::isFacing(Eigen::Vector3d point) const
+     262             :     {
+     263           0 :       Eigen::Vector3d towards_point = point - center();
+     264           0 :       double dot_product = towards_point.dot(normal());
+     265           0 :       return dot_product > 0;
+     266             :     }
+     267             : 
+     268             :     //}
+     269             : 
+     270             :     /* solidAngleRelativeTo //{ */
+     271           0 :     double Rectangle::solidAngleRelativeTo(Eigen::Vector3d point) const
+     272             :     {
+     273           0 :       Eigen::Vector3d a = point1 - point;
+     274           0 :       Eigen::Vector3d b = point2 - point;
+     275           0 :       Eigen::Vector3d c = point3 - point;
+     276           0 :       Eigen::Vector3d d = point4 - point;
+     277             : 
+     278           0 :       a.normalize();
+     279           0 :       b.normalize();
+     280           0 :       c.normalize();
+     281           0 :       d.normalize();
+     282             : 
+     283           0 :       double t1 = mrs_lib::geometry::sphericalTriangleArea(a, b, c);
+     284           0 :       double t2 = mrs_lib::geometry::sphericalTriangleArea(c, d, a);
+     285             : 
+     286           0 :       return t1 + t2;
+     287             :     }
+     288             :     //}
+     289             : 
+     290             :     //}
+     291             : 
+     292             :     /* Cuboid //{ */
+     293             : 
+     294             :     /* constructors //{ */
+     295           0 :     Cuboid::Cuboid()
+     296             :     {
+     297           0 :       for (int i = 0; i < 8; i++)
+     298             :       {
+     299           0 :         points.push_back(Eigen::Vector3d::Zero());
+     300             :       }
+     301           0 :     }
+     302             : 
+     303           0 :     Cuboid::Cuboid(Eigen::Vector3d p0, Eigen::Vector3d p1, Eigen::Vector3d p2, Eigen::Vector3d p3, Eigen::Vector3d p4, Eigen::Vector3d p5, Eigen::Vector3d p6,
+     304           0 :                    Eigen::Vector3d p7)
+     305             :     {
+     306           0 :       points.push_back(p0);
+     307           0 :       points.push_back(p1);
+     308           0 :       points.push_back(p2);
+     309           0 :       points.push_back(p3);
+     310           0 :       points.push_back(p4);
+     311           0 :       points.push_back(p5);
+     312           0 :       points.push_back(p6);
+     313           0 :       points.push_back(p7);
+     314           0 :     }
+     315             : 
+     316           0 :     Cuboid::Cuboid(std::vector<Eigen::Vector3d> points)
+     317             :     {
+     318           0 :       this->points = points;
+     319           0 :     }
+     320             : 
+     321           0 :     Cuboid::Cuboid(Eigen::Vector3d center, Eigen::Vector3d size, Eigen::Quaterniond orientation)
+     322             :     {
+     323           0 :       Eigen::Vector3d p0(size.x() / 2.0, -size.y() / 2.0, -size.z() / 2.0);
+     324           0 :       Eigen::Vector3d p1(size.x() / 2.0, size.y() / 2.0, -size.z() / 2.0);
+     325           0 :       Eigen::Vector3d p2(size.x() / 2.0, size.y() / 2.0, size.z() / 2.0);
+     326           0 :       Eigen::Vector3d p3(size.x() / 2.0, -size.y() / 2.0, size.z() / 2.0);
+     327             : 
+     328           0 :       Eigen::Vector3d p4(-size.x() / 2.0, size.y() / 2.0, -size.z() / 2.0);
+     329           0 :       Eigen::Vector3d p5(-size.x() / 2.0, -size.y() / 2.0, -size.z() / 2.0);
+     330           0 :       Eigen::Vector3d p6(-size.x() / 2.0, -size.y() / 2.0, size.z() / 2.0);
+     331           0 :       Eigen::Vector3d p7(-size.x() / 2.0, size.y() / 2.0, size.z() / 2.0);
+     332             : 
+     333           0 :       p0 = center + orientation * p0;
+     334           0 :       p1 = center + orientation * p1;
+     335           0 :       p2 = center + orientation * p2;
+     336           0 :       p3 = center + orientation * p3;
+     337             : 
+     338           0 :       p4 = center + orientation * p4;
+     339           0 :       p5 = center + orientation * p5;
+     340           0 :       p6 = center + orientation * p6;
+     341           0 :       p7 = center + orientation * p7;
+     342             : 
+     343           0 :       points.push_back(p0);
+     344           0 :       points.push_back(p1);
+     345           0 :       points.push_back(p2);
+     346           0 :       points.push_back(p3);
+     347           0 :       points.push_back(p4);
+     348           0 :       points.push_back(p5);
+     349           0 :       points.push_back(p6);
+     350           0 :       points.push_back(p7);
+     351           0 :     }
+     352             : 
+     353           0 :     Cuboid::~Cuboid()
+     354             :     {
+     355           0 :     }
+     356             :     //}
+     357             : 
+     358             :     /* lookupPoints //{ */
+     359           0 :     std::vector<Eigen::Vector3d> Cuboid::lookupPoints(int face_idx) const
+     360             :     {
+     361           0 :       std::vector<Eigen::Vector3d> lookup;
+     362           0 :       switch (face_idx)
+     363             :       {
+     364           0 :         case Cuboid::FRONT:
+     365           0 :           lookup.push_back(points[0]);
+     366           0 :           lookup.push_back(points[1]);
+     367           0 :           lookup.push_back(points[2]);
+     368           0 :           lookup.push_back(points[3]);
+     369           0 :           break;
+     370           0 :         case Cuboid::BACK:
+     371           0 :           lookup.push_back(points[4]);
+     372           0 :           lookup.push_back(points[5]);
+     373           0 :           lookup.push_back(points[6]);
+     374           0 :           lookup.push_back(points[7]);
+     375           0 :           break;
+     376           0 :         case Cuboid::LEFT:
+     377           0 :           lookup.push_back(points[1]);
+     378           0 :           lookup.push_back(points[4]);
+     379           0 :           lookup.push_back(points[7]);
+     380           0 :           lookup.push_back(points[2]);
+     381           0 :           break;
+     382           0 :         case Cuboid::RIGHT:
+     383           0 :           lookup.push_back(points[5]);
+     384           0 :           lookup.push_back(points[0]);
+     385           0 :           lookup.push_back(points[3]);
+     386           0 :           lookup.push_back(points[6]);
+     387           0 :           break;
+     388           0 :         case Cuboid::BOTTOM:
+     389           0 :           lookup.push_back(points[5]);
+     390           0 :           lookup.push_back(points[4]);
+     391           0 :           lookup.push_back(points[1]);
+     392           0 :           lookup.push_back(points[0]);
+     393           0 :           break;
+     394           0 :         case Cuboid::TOP:
+     395           0 :           lookup.push_back(points[3]);
+     396           0 :           lookup.push_back(points[2]);
+     397           0 :           lookup.push_back(points[7]);
+     398           0 :           lookup.push_back(points[6]);
+     399           0 :           break;
+     400             :       }
+     401           0 :       return lookup;
+     402             :     }
+     403             :     //}
+     404             : 
+     405             :     /* getters //{ */
+     406           0 :     const std::vector<Eigen::Vector3d> Cuboid::vertices() const
+     407             :     {
+     408           0 :       return points;
+     409             :     }
+     410             : 
+     411           0 :     const Rectangle Cuboid::getRectangle(int face_idx) const
+     412             :     {
+     413           0 :       return Rectangle(lookupPoints(face_idx));
+     414             :     }
+     415             : 
+     416           0 :     const Eigen::Vector3d Cuboid::center() const
+     417             :     {
+     418           0 :       Eigen::Vector3d point_sum = points[0];
+     419           0 :       for (int i = 1; i < 8; i++)
+     420             :       {
+     421           0 :         point_sum += points[i];
+     422             :       }
+     423           0 :       return point_sum / 8.0;
+     424             :     }
+     425             :     //}
+     426             : 
+     427             :     /* intersectionRay //{ */
+     428           0 :     const std::vector<Eigen::Vector3d> Cuboid::intersectionRay(Ray r, double epsilon) const
+     429             :     {
+     430           0 :       std::vector<Eigen::Vector3d> ret;
+     431           0 :       for (int i = 0; i < 6; i++)
+     432             :       {
+     433           0 :         Rectangle side = getRectangle(i);
+     434           0 :         auto side_intersect = side.intersectionRay(r, epsilon);
+     435           0 :         if (side_intersect != boost::none)
+     436             :         {
+     437           0 :           ret.push_back(side_intersect.get());
+     438             :         }
+     439             :       }
+     440           0 :       return ret;
+     441             :     }
+     442             :     //}
+     443             : 
+     444             :     //}
+     445             : 
+     446             :     /* Ellipse //{ */
+     447             : 
+     448             :     /* constructors //{ */
+     449           0 :     Ellipse::Ellipse()
+     450             :     {
+     451           0 :     }
+     452             : 
+     453           0 :     Ellipse::~Ellipse()
+     454             :     {
+     455           0 :     }
+     456             : 
+     457           0 :     Ellipse::Ellipse(Eigen::Vector3d center, Eigen::Quaterniond orientation, double a, double b)
+     458             :     {
+     459           0 :       center_point = center;
+     460           0 :       absolute_orientation = orientation;
+     461           0 :       major_semi = a;
+     462           0 :       minor_semi = b;
+     463           0 :     }
+     464             :     //}
+     465             : 
+     466             :     /* getters //{ */
+     467           0 :     double Ellipse::a() const
+     468             :     {
+     469           0 :       return major_semi;
+     470             :     }
+     471             : 
+     472           0 :     double Ellipse::b() const
+     473             :     {
+     474           0 :       return minor_semi;
+     475             :     }
+     476             : 
+     477           0 :     const Eigen::Vector3d Ellipse::center() const
+     478             :     {
+     479           0 :       return center_point;
+     480             :     }
+     481             : 
+     482           0 :     const Eigen::Quaterniond Ellipse::orientation() const
+     483             :     {
+     484           0 :       return absolute_orientation;
+     485             :     }
+     486             : 
+     487             :     //}
+     488             : 
+     489             :     //}
+     490             : 
+     491             :     /* Cylinder //{ */
+     492             : 
+     493             :     /* constructors //{ */
+     494           0 :     Cylinder::Cylinder()
+     495             :     {
+     496           0 :     }
+     497             : 
+     498           0 :     Cylinder::~Cylinder()
+     499             :     {
+     500           0 :     }
+     501             : 
+     502           0 :     Cylinder::Cylinder(Eigen::Vector3d center, double radius, double height, Eigen::Quaterniond orientation)
+     503             :     {
+     504           0 :       this->center_point = center;
+     505           0 :       this->radius = radius;
+     506           0 :       this->height = height;
+     507           0 :       this->absolute_orientation = orientation;
+     508           0 :     }
+     509             :     //}
+     510             : 
+     511             :     /* getters //{ */
+     512           0 :     const Eigen::Vector3d Cylinder::center() const
+     513             :     {
+     514           0 :       return center_point;
+     515             :     }
+     516             : 
+     517           0 :     const Eigen::Quaterniond Cylinder::orientation() const
+     518             :     {
+     519           0 :       return absolute_orientation;
+     520             :     }
+     521             : 
+     522           0 :     double Cylinder::r() const
+     523             :     {
+     524           0 :       return radius;
+     525             :     }
+     526             : 
+     527           0 :     double Cylinder::h() const
+     528             :     {
+     529           0 :       return height;
+     530             :     }
+     531             : 
+     532           0 :     const Ellipse Cylinder::getCap(int index) const
+     533             :     {
+     534           0 :       Ellipse e;
+     535           0 :       Eigen::Vector3d ellipse_center;
+     536           0 :       switch (index)
+     537             :       {
+     538           0 :         case Cylinder::BOTTOM:
+     539           0 :           ellipse_center = center() - orientation() * (Eigen::Vector3d::UnitZ() * (h() / 2.0));
+     540           0 :           e = Ellipse(ellipse_center, orientation(), r(), r());
+     541           0 :           break;
+     542           0 :         case Cylinder::TOP:
+     543           0 :           ellipse_center = center() + orientation() * (Eigen::Vector3d::UnitZ() * (h() / 2.0));
+     544           0 :           e = Ellipse(ellipse_center, orientation(), r(), r());
+     545           0 :           break;
+     546             :       }
+     547           0 :       return e;
+     548             :     }
+     549             : 
+     550             :     //}
+     551             : 
+     552             :     //}
+     553             : 
+     554             :     /* Cone //{ */
+     555             : 
+     556             :     /* constructors //{ */
+     557           0 :     Cone::Cone()
+     558             :     {
+     559           0 :     }
+     560             : 
+     561           0 :     Cone::~Cone()
+     562             :     {
+     563           0 :     }
+     564             : 
+     565           0 :     Cone::Cone(Eigen::Vector3d origin_point, double angle, double height, Eigen::Vector3d absolute_direction)
+     566             :     {
+     567           0 :       this->origin_point = origin_point;
+     568           0 :       this->angle = angle;
+     569           0 :       this->height = height;
+     570           0 :       this->absolute_direction = absolute_direction.normalized();
+     571           0 :     }
+     572             :     //}
+     573             : 
+     574             :     /* getters //{ */
+     575           0 :     const Eigen::Vector3d Cone::origin() const
+     576             :     {
+     577           0 :       return origin_point;
+     578             :     }
+     579             : 
+     580           0 :     const Eigen::Vector3d Cone::direction() const
+     581             :     {
+     582           0 :       return absolute_direction;
+     583             :     }
+     584             : 
+     585           0 :     const Eigen::Vector3d Cone::center() const
+     586             :     {
+     587           0 :       return origin() + (0.5 * h()) * direction();
+     588             :     }
+     589             : 
+     590           0 :     double Cone::theta() const
+     591             :     {
+     592           0 :       return angle;
+     593             :     }
+     594             : 
+     595           0 :     double Cone::h() const
+     596             :     {
+     597           0 :       return height;
+     598             :     }
+     599             : 
+     600           0 :     const Ellipse Cone::getCap() const
+     601             :     {
+     602           0 :       Eigen::Vector3d ellipse_center = origin() + direction() * h();
+     603           0 :       Eigen::Quaterniond ellipse_orientation = Eigen::Quaterniond::FromTwoVectors(Eigen::Vector3d::UnitZ(), direction());
+     604           0 :       double cap_radius = std::tan(theta()) * h();
+     605           0 :       Ellipse e(ellipse_center, ellipse_orientation, cap_radius, cap_radius);
+     606           0 :       return e;
+     607             :     }
+     608             : 
+     609           0 :     const std::optional<Eigen::Vector3d> Cone::projectPoint(const Eigen::Vector3d& point) const
+     610             :     {
+     611             : 
+     612           0 :       Eigen::Vector3d point_vec = point - origin();
+     613           0 :       double point_axis_angle = acos((point_vec.dot(direction())) / (point_vec.norm() * direction().norm()));
+     614             : 
+     615             :       /* Eigen::Vector3d axis_projection = this->cone_axis_projector * point_vec + origin(); */
+     616             : 
+     617           0 :       Eigen::Vector3d axis_rot = direction().cross(point_vec);
+     618           0 :       axis_rot.normalize();
+     619             : 
+     620           0 :       Eigen::AngleAxis<double> my_quat(this->angle - point_axis_angle, axis_rot);
+     621             : 
+     622           0 :       Eigen::Vector3d point_on_cone = my_quat * point_vec + origin();
+     623             : 
+     624           0 :       Eigen::Vector3d vec_point_on_cone = point_on_cone - origin();
+     625           0 :       vec_point_on_cone.normalize();
+     626             : 
+     627           0 :       double beta = this->angle - point_axis_angle;
+     628             : 
+     629           0 :       if (point_axis_angle < this->angle)
+     630             :       {
+     631           0 :         return origin() + vec_point_on_cone * cos(beta) * point_vec.norm();
+     632           0 :       } else if ((point_axis_angle >= this->angle) && (point_axis_angle - this->angle) <= M_PI / 2.0)
+     633             :       {  // TODO: is this condition correct?
+     634           0 :         return origin() + vec_point_on_cone * cos(point_axis_angle - this->angle) * point_vec.norm();
+     635             :       } else
+     636             :       {
+     637           0 :         return {};
+     638             :       }
+     639             :     }
+     640             : 
+     641             :     //}
+     642             : 
+     643             :     //}
+     644             : 
+     645             :   }  // namespace geometry
+     646             : }  // namespace mrs_lib
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/math/index-sort-f.html b/mrs_lib/src/math/index-sort-f.html new file mode 100644 index 0000000000..ca590b81a9 --- /dev/null +++ b/mrs_lib/src/math/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/math + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/mathHitTotalCoverage
Test:coverage.infoLines:1717100.0 %
Date:2023-11-29 14:09:54Functions:11100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
math.cpp +
100.0%
+
100.0 %17 / 17100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/math/index-sort-l.html b/mrs_lib/src/math/index-sort-l.html new file mode 100644 index 0000000000..11e3408e97 --- /dev/null +++ b/mrs_lib/src/math/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/math + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/mathHitTotalCoverage
Test:coverage.infoLines:1717100.0 %
Date:2023-11-29 14:09:54Functions:11100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
math.cpp +
100.0%
+
100.0 %17 / 17100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/math/index.html b/mrs_lib/src/math/index.html new file mode 100644 index 0000000000..5c0725677c --- /dev/null +++ b/mrs_lib/src/math/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/math + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/mathHitTotalCoverage
Test:coverage.infoLines:1717100.0 %
Date:2023-11-29 14:09:54Functions:11100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
math.cpp +
100.0%
+
100.0 %17 / 17100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/math/math.cpp.func-sort-c.html b/mrs_lib/src/math/math.cpp.func-sort-c.html new file mode 100644 index 0000000000..bc7cec4e75 --- /dev/null +++ b/mrs_lib/src/math/math.cpp.func-sort-c.html @@ -0,0 +1,76 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/math/math.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/math - math.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:1717100.0 %
Date:2023-11-29 14:09:54Functions:11100.0 %
+
+ +
+ + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib6probitEd202
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/math/math.cpp.func.html b/mrs_lib/src/math/math.cpp.func.html new file mode 100644 index 0000000000..449b864151 --- /dev/null +++ b/mrs_lib/src/math/math.cpp.func.html @@ -0,0 +1,76 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/math/math.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/math - math.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:1717100.0 %
Date:2023-11-29 14:09:54Functions:11100.0 %
+
+ +
+ + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib6probitEd202
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/math/math.cpp.gcov.html b/mrs_lib/src/math/math.cpp.gcov.html new file mode 100644 index 0000000000..6d98dc948a --- /dev/null +++ b/mrs_lib/src/math/math.cpp.gcov.html @@ -0,0 +1,141 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/math/math.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/math - math.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:1717100.0 %
Date:2023-11-29 14:09:54Functions:11100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_lib/math.h>
+       2             : 
+       3             : namespace mrs_lib
+       4             : {
+       5             :   /* probit() function //{ */
+       6         202 :   double probit(const double quantile)
+       7             :   {
+       8             :     // polynomial coefficients of the numerator for rational polynomial approximation in the range (0.08; 0.92)
+       9             :     constexpr double a[4] =
+      10             :     {
+      11             :       2.50662823884,
+      12             :     -18.61500062529,
+      13             :      41.39119773534,
+      14             :     -25.44106049637
+      15             :     };
+      16             : 
+      17             :     // polynomial coefficients of the denominator for the rational polynomial approximation in the range (0.08; 0.92)
+      18             :     constexpr double b[4] =
+      19             :     {
+      20             :       -8.47351093090,
+      21             :       23.08336743743,
+      22             :      -21.06224101826,
+      23             :        3.13082909833
+      24             :     };
+      25             : 
+      26             :     // polynomial coefficients of the logarithmical approximation in the range (0; 0.08) U (0.92; 1)
+      27             :     constexpr double c[9] =
+      28             :     {
+      29             :       0.3374754822726147,
+      30             :       0.9761690190917186,
+      31             :       0.1607979714918209,
+      32             :       0.0276438810333863,
+      33             :       0.0038405729373609,
+      34             :       0.0003951896511919,
+      35             :       0.0000321767881768,
+      36             :       0.0000002888167364,
+      37             :       0.0000003960315187
+      38             :     };
+      39             : 
+      40             :     // correctly handle special values
+      41         202 :     if (quantile == 1.0)
+      42           1 :       return std::numeric_limits<double>::infinity();
+      43         201 :     if (quantile == 0.0)
+      44           1 :       return -std::numeric_limits<double>::infinity();
+      45         200 :     if (quantile < 0.0 || quantile > 1.0)
+      46           2 :       return std::numeric_limits<double>::quiet_NaN();
+      47             : 
+      48         198 :     const double y = quantile - 0.5;
+      49         198 :     if (std::abs(y) < 0.42)
+      50             :     {
+      51         168 :       const double r = y*y;
+      52         168 :       const double num = y*((( a[3]*r + a[2] )*r + a[1])*r + a[0]);
+      53         168 :       const double denom = (((( b[3]*r + b[2] )*r + b[1])*r + b[0])*r + 1);
+      54         168 :       return num/denom;
+      55             :     }
+      56             :     else
+      57             :     {
+      58          30 :       const double v = y > 0 ? 1.0 - quantile : quantile;
+      59          30 :       const double r = std::log(-std::log(v));
+      60          30 :       const double x = c[0] + r*( c[1] + r*( c[2] + r*( c[3] + r*( c[4] + r*( c[5] + r*( c[6] + r*( c[7] + r*c[8] )))))));
+      61          30 :       return y < 0 ? -x : x;
+      62             :     }
+      63             :   }
+      64             :   //}
+      65             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/median_filter/index-sort-f.html b/mrs_lib/src/median_filter/index-sort-f.html new file mode 100644 index 0000000000..0da8c40bcc --- /dev/null +++ b/mrs_lib/src/median_filter/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/median_filter + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/median_filterHitTotalCoverage
Test:coverage.infoLines:829289.1 %
Date:2023-11-29 14:09:54Functions:161794.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
median_filter.cpp +
89.1%89.1%
+
89.1 %82 / 9294.1 %16 / 17
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/median_filter/index-sort-l.html b/mrs_lib/src/median_filter/index-sort-l.html new file mode 100644 index 0000000000..091d29fc7e --- /dev/null +++ b/mrs_lib/src/median_filter/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/median_filter + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/median_filterHitTotalCoverage
Test:coverage.infoLines:829289.1 %
Date:2023-11-29 14:09:54Functions:161794.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
median_filter.cpp +
89.1%89.1%
+
89.1 %82 / 9294.1 %16 / 17
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/median_filter/index.html b/mrs_lib/src/median_filter/index.html new file mode 100644 index 0000000000..42b80d54fe --- /dev/null +++ b/mrs_lib/src/median_filter/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/median_filter + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/median_filterHitTotalCoverage
Test:coverage.infoLines:829289.1 %
Date:2023-11-29 14:09:54Functions:161794.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
median_filter.cpp +
89.1%89.1%
+
89.1 %82 / 9294.1 %16 / 17
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/median_filter/median_filter.cpp.func-sort-c.html b/mrs_lib/src/median_filter/median_filter.cpp.func-sort-c.html new file mode 100644 index 0000000000..3fcd7700d8 --- /dev/null +++ b/mrs_lib/src/median_filter/median_filter.cpp.func-sort-c.html @@ -0,0 +1,140 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/median_filter/median_filter.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/median_filter - median_filter.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:829289.1 %
Date:2023-11-29 14:09:54Functions:161794.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib12MedianFilteraSEOS0_0
_ZN7mrs_lib12MedianFilterC2EOS0_1
_ZN7mrs_lib12MedianFilterC2ERKS0_1
_ZN7mrs_lib12MedianFilterC2Ev1
_ZNK7mrs_lib12MedianFilter11initializedEv1
_ZN7mrs_lib12MedianFilter11setMaxValueEd2
_ZN7mrs_lib12MedianFilter11setMinValueEd2
_ZN7mrs_lib12MedianFilter15setBufferLengthEm2
_ZN7mrs_lib12MedianFilter16setMaxDifferenceEd2
_ZN7mrs_lib12MedianFilter5clearEv2
_ZN7mrs_lib12MedianFilteraSERKS0_2
_ZN7mrs_lib12MedianFilterC2Emddd4
_ZNK7mrs_lib12MedianFilter4fullEv21
_ZN7mrs_lib12MedianFilter3addEd26
_ZN7mrs_lib12MedianFilter8addCheckEd26
_ZN7mrs_lib12MedianFilter5checkEd30
_ZNK7mrs_lib12MedianFilter6medianEv46
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/median_filter/median_filter.cpp.func.html b/mrs_lib/src/median_filter/median_filter.cpp.func.html new file mode 100644 index 0000000000..e4985e6086 --- /dev/null +++ b/mrs_lib/src/median_filter/median_filter.cpp.func.html @@ -0,0 +1,140 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/median_filter/median_filter.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/median_filter - median_filter.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:829289.1 %
Date:2023-11-29 14:09:54Functions:161794.1 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib12MedianFilter11setMaxValueEd2
_ZN7mrs_lib12MedianFilter11setMinValueEd2
_ZN7mrs_lib12MedianFilter15setBufferLengthEm2
_ZN7mrs_lib12MedianFilter16setMaxDifferenceEd2
_ZN7mrs_lib12MedianFilter3addEd26
_ZN7mrs_lib12MedianFilter5checkEd30
_ZN7mrs_lib12MedianFilter5clearEv2
_ZN7mrs_lib12MedianFilter8addCheckEd26
_ZN7mrs_lib12MedianFilterC2EOS0_1
_ZN7mrs_lib12MedianFilterC2ERKS0_1
_ZN7mrs_lib12MedianFilterC2Emddd4
_ZN7mrs_lib12MedianFilterC2Ev1
_ZN7mrs_lib12MedianFilteraSEOS0_0
_ZN7mrs_lib12MedianFilteraSERKS0_2
_ZNK7mrs_lib12MedianFilter11initializedEv1
_ZNK7mrs_lib12MedianFilter4fullEv21
_ZNK7mrs_lib12MedianFilter6medianEv46
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/median_filter/median_filter.cpp.gcov.html b/mrs_lib/src/median_filter/median_filter.cpp.gcov.html new file mode 100644 index 0000000000..eb84428de8 --- /dev/null +++ b/mrs_lib/src/median_filter/median_filter.cpp.gcov.html @@ -0,0 +1,278 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/median_filter/median_filter.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/median_filter - median_filter.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:829289.1 %
Date:2023-11-29 14:09:54Functions:161794.1 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_lib/median_filter.h>
+       2             : 
+       3             : namespace mrs_lib
+       4             : {
+       5             :   /* constructor overloads //{ */
+       6             : 
+       7           4 :   MedianFilter::MedianFilter(const size_t buffer_length, const double min_value, const double max_value, const double max_diff)
+       8             :     : m_median(std::nullopt),
+       9             :       m_min_valid(min_value),
+      10             :       m_max_valid(max_value),
+      11           4 :       m_max_diff(max_diff)
+      12             :   {
+      13           4 :     m_buffer.set_capacity(buffer_length);
+      14           4 :     m_buffer_sorted.reserve(buffer_length);
+      15           4 :   }
+      16             : 
+      17           1 :   MedianFilter::MedianFilter()
+      18             :     : m_median(std::nullopt),
+      19             :       m_min_valid(0.0),
+      20             :       m_max_valid(0.0),
+      21           1 :       m_max_diff(0.0)
+      22             :   {
+      23           1 :     m_buffer.set_capacity(0);
+      24           1 :   }
+      25             : 
+      26           1 :   MedianFilter::MedianFilter(const MedianFilter& other)
+      27             :   {
+      28           1 :     *this = other;
+      29           1 :   }
+      30             : 
+      31           1 :   MedianFilter::MedianFilter(MedianFilter&& other)
+      32             :   {
+      33           1 :     *this = other;
+      34           1 :   }
+      35             : 
+      36             :   //}
+      37             : 
+      38             :   /* operator=() method and overloads //{ */
+      39           2 :   MedianFilter& MedianFilter::operator=(const MedianFilter& other)
+      40             :   {
+      41           2 :     std::scoped_lock lck(other.m_mtx, m_mtx);
+      42             :   
+      43           2 :     m_buffer = other.m_buffer;
+      44           2 :     m_buffer_sorted = other.m_buffer_sorted;
+      45           2 :     m_median = other.m_median;
+      46             :   
+      47             :     // parameters specified by the user
+      48           2 :     m_min_valid = other.m_min_valid;
+      49           2 :     m_max_valid = other.m_max_valid;
+      50           2 :     m_max_diff = other.m_max_diff;
+      51             :   
+      52           4 :     return *this;
+      53             :   }
+      54             : 
+      55           0 :   MedianFilter& MedianFilter::operator=(MedianFilter&& other)
+      56             :   {
+      57           0 :     std::scoped_lock lck(other.m_mtx, m_mtx);
+      58             : 
+      59           0 :     m_buffer = std::move(other.m_buffer);
+      60           0 :     m_buffer_sorted = std::move(other.m_buffer_sorted);
+      61           0 :     m_median = std::move(other.m_median);
+      62             : 
+      63             :     // parameters specified by the user
+      64           0 :     m_min_valid = other.m_min_valid;
+      65           0 :     m_max_valid = other.m_max_valid;
+      66           0 :     m_max_diff = other.m_max_diff;
+      67             : 
+      68           0 :     return *this;
+      69             :   }
+      70             :   //}
+      71             : 
+      72             :   /* add() method //{ */
+      73          26 :   void MedianFilter::add(const double value)
+      74             :   {
+      75          52 :     std::scoped_lock lck(m_mtx);
+      76             :     // add the value to the buffer
+      77          26 :     m_buffer.push_back(value);
+      78             :     // reset the cached median value
+      79          26 :     m_median = std::nullopt;
+      80          26 :   }
+      81             :   //}
+      82             : 
+      83             :   /* check() method //{ */
+      84          30 :   bool MedianFilter::check(const double value)
+      85             :   {
+      86          30 :     std::scoped_lock lck(m_mtx);
+      87             :     // check if all constraints are met
+      88          30 :     const double diff = m_buffer.empty() ? 0.0 : std::abs(median() - value);
+      89          60 :     return value > m_min_valid && value < m_max_valid && diff < m_max_diff;
+      90             :   }
+      91             :   //}
+      92             : 
+      93             :   /* addCheck() method //{ */
+      94          26 :   bool MedianFilter::addCheck(const double value)
+      95             :   {
+      96          52 :     std::scoped_lock lck(m_mtx);
+      97          26 :     add(value);
+      98          52 :     return check(value);
+      99             :   }
+     100             :   //}
+     101             : 
+     102             :   /* clear() method //{ */
+     103           2 :   void MedianFilter::clear()
+     104             :   {
+     105           4 :     std::scoped_lock lck(m_mtx);
+     106           2 :     m_median = std::nullopt;
+     107           2 :     m_buffer.clear();
+     108           2 :   }
+     109             :   //}
+     110             : 
+     111             :   /* full() method //{ */
+     112          21 :   bool MedianFilter::full() const
+     113             :   {
+     114          42 :     std::scoped_lock lck(m_mtx);
+     115          42 :     return m_buffer.full();
+     116             :   }
+     117             :   //}
+     118             : 
+     119             :   /* median() method //{ */
+     120          46 :   double MedianFilter::median() const
+     121             :   {
+     122          92 :     std::scoped_lock lck(m_mtx);
+     123             :     // if the value was already calculated, just return it
+     124          46 :     if (m_median.has_value())
+     125          17 :       return m_median.value();
+     126             :   
+     127             :     // check if there are even any numbers to calculate the median from
+     128          29 :     if (m_buffer.empty())
+     129             :     {
+     130           4 :       m_median = std::numeric_limits<double>::quiet_NaN();
+     131           4 :       return m_median.value();
+     132             :     }
+     133             :   
+     134             :     // remove any elements from buffer_sorted
+     135          25 :     m_buffer_sorted.clear();
+     136             :     // copy all elements from the input buffer to buffer_sorted
+     137          25 :     m_buffer_sorted.insert(std::end(m_buffer_sorted), std::begin(m_buffer), std::end(m_buffer));
+     138             :     // check for the special case of the median when there is an even number of numbers in the set
+     139          25 :     const bool even_set = m_buffer_sorted.size() % 2 == 0;
+     140             :   
+     141             :     // if it's an even set, we'll need one more element sorted than for an odd set of numbers
+     142          25 :     const size_t median_pos = even_set ? std::ceil(m_buffer_sorted.size()/2.0) : std::floor(m_buffer_sorted.size()/2.0);
+     143             :     // actually sort the elements in buffer_sorted up to the n-th element
+     144          25 :     std::nth_element(std::begin(m_buffer_sorted), std::begin(m_buffer_sorted)+median_pos, std::end(m_buffer_sorted));
+     145             :   
+     146             :     // special case for a median of an even set of numbers
+     147          25 :     if (even_set)
+     148           9 :       m_median = (m_buffer_sorted.at(median_pos) + m_buffer_sorted.at(median_pos-1))/2.0;
+     149             :     // the "normal" case with an odd set
+     150             :     else
+     151          16 :       m_median = m_buffer_sorted.at(median_pos);
+     152             :     // return the now-cached value
+     153          25 :     return m_median.value();
+     154             :   }
+     155             :   //}
+     156             : 
+     157             :   /* initialized() method //{ */
+     158           1 :   bool MedianFilter::initialized() const
+     159             :   {
+     160           1 :     std::scoped_lock lck(m_mtx);
+     161           2 :     return m_buffer.size() > 0;
+     162             :   }
+     163             :   //}
+     164             : 
+     165             :   /* setBufferLength() method //{ */
+     166           2 :   void MedianFilter::setBufferLength(const size_t buffer_length)
+     167             :   {
+     168           4 :     std::scoped_lock lck(m_mtx);
+     169             :     // the median may change if the some values are discarded
+     170           2 :     if (buffer_length < m_buffer.size())
+     171           0 :       m_median = std::nullopt;
+     172             :   
+     173           2 :     m_buffer.set_capacity(buffer_length);
+     174           2 :     m_buffer_sorted.reserve(buffer_length);
+     175           2 :   }
+     176             :   //}
+     177             : 
+     178             :   /* setMinValue() method //{ */
+     179           2 :   void MedianFilter::setMinValue(const double min_value)
+     180             :   {
+     181           2 :     std::scoped_lock lck(m_mtx);
+     182           2 :     m_min_valid = min_value;
+     183           2 :   }
+     184             :   //}
+     185             : 
+     186             :   /* setMaxValue() method //{ */
+     187           2 :   void MedianFilter::setMaxValue(const double max_value)
+     188             :   {
+     189           2 :     std::scoped_lock lck(m_mtx);
+     190           2 :     m_max_valid = max_value;
+     191           2 :   }
+     192             :   //}
+     193             : 
+     194             :   /* setMaxDifference() method //{ */
+     195           2 :   void MedianFilter::setMaxDifference(const double max_diff)
+     196             :   {
+     197           2 :     std::scoped_lock lck(m_mtx);
+     198           2 :     m_max_diff = max_diff;
+     199           2 :   }
+     200             :   //}
+     201             : 
+     202             : } // namespace mrs_lib
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/param_loader/index-sort-f.html b/mrs_lib/src/param_loader/index-sort-f.html new file mode 100644 index 0000000000..8a7f6463ee --- /dev/null +++ b/mrs_lib/src/param_loader/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/param_loader + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/param_loaderHitTotalCoverage
Test:coverage.infoLines:395570.9 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
param_provider.cpp +
70.9%70.9%
+
70.9 %39 / 55100.0 %4 / 4
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/param_loader/index-sort-l.html b/mrs_lib/src/param_loader/index-sort-l.html new file mode 100644 index 0000000000..4ad13dd944 --- /dev/null +++ b/mrs_lib/src/param_loader/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/param_loader + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/param_loaderHitTotalCoverage
Test:coverage.infoLines:395570.9 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
param_provider.cpp +
70.9%70.9%
+
70.9 %39 / 55100.0 %4 / 4
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/param_loader/index.html b/mrs_lib/src/param_loader/index.html new file mode 100644 index 0000000000..57e0d36e25 --- /dev/null +++ b/mrs_lib/src/param_loader/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/param_loader + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/param_loaderHitTotalCoverage
Test:coverage.infoLines:395570.9 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
param_provider.cpp +
70.9%70.9%
+
70.9 %39 / 55100.0 %4 / 4
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/param_loader/param_provider.cpp.func-sort-c.html b/mrs_lib/src/param_loader/param_provider.cpp.func-sort-c.html new file mode 100644 index 0000000000..53332cdc19 --- /dev/null +++ b/mrs_lib/src/param_loader/param_provider.cpp.func-sort-c.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/param_loader/param_provider.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/param_loader - param_provider.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:395570.9 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK7mrs_lib13ParamProvider8getParamERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN6XmlRpc11XmlRpcValueE1
_ZN7mrs_lib13ParamProvider11addYamlFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib13ParamProviderC2ERKN3ros10NodeHandleENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb2
_ZNK7mrs_lib13ParamProvider12findYamlNodeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE13
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/param_loader/param_provider.cpp.func.html b/mrs_lib/src/param_loader/param_provider.cpp.func.html new file mode 100644 index 0000000000..9ef8065b51 --- /dev/null +++ b/mrs_lib/src/param_loader/param_provider.cpp.func.html @@ -0,0 +1,88 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/param_loader/param_provider.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/param_loader - param_provider.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:395570.9 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib13ParamProvider11addYamlFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib13ParamProviderC2ERKN3ros10NodeHandleENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEb2
_ZNK7mrs_lib13ParamProvider12findYamlNodeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE13
_ZNK7mrs_lib13ParamProvider8getParamERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN6XmlRpc11XmlRpcValueE1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/param_loader/param_provider.cpp.gcov.html b/mrs_lib/src/param_loader/param_provider.cpp.gcov.html new file mode 100644 index 0000000000..1e8692c2a2 --- /dev/null +++ b/mrs_lib/src/param_loader/param_provider.cpp.gcov.html @@ -0,0 +1,192 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/param_loader/param_provider.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/param_loader - param_provider.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:395570.9 %
Date:2023-11-29 14:09:54Functions:44100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_lib/param_provider.h>
+       2             : 
+       3             : namespace mrs_lib
+       4             : {
+       5             :   // Explicit instantiation of the tepmplated functions to precompile them into mrs_lib and speed up compilation of user program.
+       6             :   // Instantiating these functions should be sufficient to invoke precompilation of all templated ParamLoader functions.
+       7             : 
+       8             :   template bool ParamProvider::getParam<bool>(const std::string& name, bool& out_value) const;
+       9             :   template bool ParamProvider::getParam<int>(const std::string& name, int& out_value) const;
+      10             :   template bool ParamProvider::getParam<double>(const std::string& name, double& out_value) const;
+      11             :   template bool ParamProvider::getParam<std::string>(const std::string& name, std::string& out_value) const;
+      12             : 
+      13           2 :   ParamProvider::ParamProvider(const ros::NodeHandle& nh, std::string node_name, const bool use_rosparam)
+      14           2 :   : m_nh(nh), m_node_name(std::move(node_name)), m_use_rosparam(use_rosparam)
+      15             :   {
+      16           2 :   }
+      17             : 
+      18           2 :   bool ParamProvider::addYamlFile(const std::string& filepath)
+      19             :   {
+      20             :     try
+      21             :     {
+      22           4 :       const auto loaded_yaml = YAML::LoadFile(filepath);
+      23           2 :       YAML::Node root;
+      24           2 :       root["root"] = loaded_yaml;
+      25           2 :       m_yamls.emplace_back(root);
+      26           2 :       return true;
+      27             :     }
+      28           0 :     catch (const YAML::ParserException& e)
+      29             :     {
+      30           0 :       ROS_ERROR_STREAM("[" << m_node_name << "]: Failed to parse file \"" << filepath << "\"! Parameters will not be loaded: " << e.what());
+      31           0 :       return false;
+      32             :     }
+      33           0 :     catch (const YAML::BadFile& e)
+      34             :     {
+      35           0 :       ROS_ERROR_STREAM("[" << m_node_name << "]: File \"" << filepath << "\" does not exist! Parameters will not be loaded: " << e.what());
+      36           0 :       return false;
+      37             :     }
+      38           0 :     catch (const YAML::Exception& e)
+      39             :     {
+      40           0 :       ROS_ERROR_STREAM("[" << m_node_name << "]: YAML-CPP threw an exception! Parameters will not be loaded: " << e.what());
+      41           0 :       return false;
+      42             :     }
+      43             :     return false;
+      44             :   }
+      45             : 
+      46           1 :   bool ParamProvider::getParam(const std::string& param_name, XmlRpc::XmlRpcValue& value_out) const
+      47             :   {
+      48           1 :     if (m_use_rosparam && m_nh.getParam(param_name, value_out))
+      49           1 :       return true;
+      50             : 
+      51             :     try
+      52             :     {
+      53           0 :       const auto found_node = findYamlNode(param_name);
+      54           0 :       if (found_node.has_value())
+      55           0 :         ROS_WARN_STREAM("[" << m_node_name << "]: Parameter \"" << param_name << "\" of desired type XmlRpc::XmlRpcValue is only available as a static parameter, which doesn't support loading of this type.");
+      56             :     }
+      57           0 :     catch (const YAML::Exception& e)
+      58             :     {
+      59           0 :       ROS_ERROR_STREAM("[" << m_node_name << "]: YAML-CPP threw an unknown exception: " << e.what());
+      60             :     }
+      61           0 :     return false;
+      62             :   }
+      63             : 
+      64          13 :   std::optional<YAML::Node> ParamProvider::findYamlNode(const std::string& param_name) const
+      65             :   {
+      66          16 :     for (const auto& yaml : m_yamls)
+      67             :     {
+      68             :       // Try to load the parameter sequentially as a map.
+      69           5 :       auto cur_node_it = std::cbegin(yaml);
+      70             :       // The root should always be a pam
+      71           5 :       if (!cur_node_it->second.IsMap())
+      72           0 :         continue;
+      73             : 
+      74           5 :       bool loaded = true;
+      75             :       {
+      76           5 :         constexpr char delimiter = '/';
+      77           5 :         auto substr_start = std::cbegin(param_name);
+      78           5 :         auto substr_end = substr_start;
+      79           2 :         do
+      80             :         {
+      81           7 :           substr_end = std::find(substr_start, std::cend(param_name), delimiter);
+      82             :           // why can't substr or string_view take iterators? :'(
+      83           7 :           const auto start_pos = std::distance(std::cbegin(param_name), substr_start);
+      84           7 :           const auto count = std::distance(substr_start, substr_end);
+      85           7 :           const std::string param_substr = param_name.substr(start_pos, count);
+      86           7 :           substr_start = substr_end+1;
+      87             : 
+      88           7 :           bool found = false;
+      89          25 :           for (auto node_it = std::cbegin(cur_node_it->second); node_it != std::cend(cur_node_it->second); ++node_it)
+      90             :           {
+      91          11 :             if (node_it->first.as<std::string>() == param_substr)
+      92             :             {
+      93           4 :               cur_node_it = node_it;
+      94           4 :               found = true;
+      95           4 :               break;
+      96             :             }
+      97             :           }
+      98             : 
+      99           7 :           if (!found)
+     100             :           {
+     101           3 :             loaded = false;
+     102           3 :             break;
+     103             :           }
+     104             :         }
+     105           4 :         while (substr_end != std::end(param_name) && cur_node_it->second.IsMap());
+     106             :       }
+     107             : 
+     108           5 :       if (loaded)
+     109             :       {
+     110           4 :         return cur_node_it->second;
+     111             :       }
+     112             :     }
+     113             : 
+     114          11 :     return std::nullopt;
+     115             :   }
+     116             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timeout_manager/index-sort-f.html b/mrs_lib/src/timeout_manager/index-sort-f.html new file mode 100644 index 0000000000..41d07281a5 --- /dev/null +++ b/mrs_lib/src/timeout_manager/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timeout_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timeout_managerHitTotalCoverage
Test:coverage.infoLines:496279.0 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
timeout_manager.cpp +
79.0%79.0%
+
79.0 %49 / 6281.8 %9 / 11
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timeout_manager/index-sort-l.html b/mrs_lib/src/timeout_manager/index-sort-l.html new file mode 100644 index 0000000000..60448d1844 --- /dev/null +++ b/mrs_lib/src/timeout_manager/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timeout_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timeout_managerHitTotalCoverage
Test:coverage.infoLines:496279.0 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
timeout_manager.cpp +
79.0%79.0%
+
79.0 %49 / 6281.8 %9 / 11
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timeout_manager/index.html b/mrs_lib/src/timeout_manager/index.html new file mode 100644 index 0000000000..cc24a374e9 --- /dev/null +++ b/mrs_lib/src/timeout_manager/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timeout_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timeout_managerHitTotalCoverage
Test:coverage.infoLines:496279.0 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
timeout_manager.cpp +
79.0%79.0%
+
79.0 %49 / 6281.8 %9 / 11
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timeout_manager/timeout_manager.cpp.func-sort-c.html b/mrs_lib/src/timeout_manager/timeout_manager.cpp.func-sort-c.html new file mode 100644 index 0000000000..46234c44ba --- /dev/null +++ b/mrs_lib/src/timeout_manager/timeout_manager.cpp.func-sort-c.html @@ -0,0 +1,116 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timeout_manager/timeout_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timeout_manager - timeout_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:496279.0 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib14TimeoutManager6changeEmRKN3ros8DurationERKSt8functionIFvRKNS1_4TimeEEES8_bb0
_ZN7mrs_lib14TimeoutManager9lastResetEm0
_ZN7mrs_lib14TimeoutManager8pauseAllEv2
_ZN7mrs_lib14TimeoutManagerC2ERKN3ros10NodeHandleERKNS1_4RateE2
_ZN7mrs_lib14TimeoutManager8startAllERKN3ros4TimeE4
_ZN7mrs_lib14TimeoutManager11registerNewERKN3ros8DurationERKSt8functionIFvRKNS1_4TimeEEES8_bb5
_ZN7mrs_lib14TimeoutManager5startEmRKN3ros4TimeE5
_ZN7mrs_lib14TimeoutManager5pauseEm9
_ZN7mrs_lib14TimeoutManager5resetEmRKN3ros4TimeE808
_ZN7mrs_lib14TimeoutManager7startedEm1588
_ZN7mrs_lib14TimeoutManager19main_timer_callbackERKN3ros10TimerEventE2098
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timeout_manager/timeout_manager.cpp.func.html b/mrs_lib/src/timeout_manager/timeout_manager.cpp.func.html new file mode 100644 index 0000000000..2229d1e6a1 --- /dev/null +++ b/mrs_lib/src/timeout_manager/timeout_manager.cpp.func.html @@ -0,0 +1,116 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timeout_manager/timeout_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timeout_manager - timeout_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:496279.0 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib14TimeoutManager11registerNewERKN3ros8DurationERKSt8functionIFvRKNS1_4TimeEEES8_bb5
_ZN7mrs_lib14TimeoutManager19main_timer_callbackERKN3ros10TimerEventE2098
_ZN7mrs_lib14TimeoutManager5pauseEm9
_ZN7mrs_lib14TimeoutManager5resetEmRKN3ros4TimeE808
_ZN7mrs_lib14TimeoutManager5startEmRKN3ros4TimeE5
_ZN7mrs_lib14TimeoutManager6changeEmRKN3ros8DurationERKSt8functionIFvRKNS1_4TimeEEES8_bb0
_ZN7mrs_lib14TimeoutManager7startedEm1588
_ZN7mrs_lib14TimeoutManager8pauseAllEv2
_ZN7mrs_lib14TimeoutManager8startAllERKN3ros4TimeE4
_ZN7mrs_lib14TimeoutManager9lastResetEm0
_ZN7mrs_lib14TimeoutManagerC2ERKN3ros10NodeHandleERKNS1_4RateE2
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timeout_manager/timeout_manager.cpp.gcov.html b/mrs_lib/src/timeout_manager/timeout_manager.cpp.gcov.html new file mode 100644 index 0000000000..6cba5e4db4 --- /dev/null +++ b/mrs_lib/src/timeout_manager/timeout_manager.cpp.gcov.html @@ -0,0 +1,178 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timeout_manager/timeout_manager.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timeout_manager - timeout_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:496279.0 %
Date:2023-11-29 14:09:54Functions:91181.8 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_lib/timeout_manager.h>
+       2             : 
+       3             : namespace mrs_lib
+       4             : {
+       5             : 
+       6           2 :   TimeoutManager::TimeoutManager(const ros::NodeHandle& nh, const ros::Rate& update_rate)
+       7           2 :     : m_last_id(0)
+       8             :   {
+       9           2 :     m_main_timer = nh.createTimer(update_rate, &TimeoutManager::main_timer_callback, this);
+      10           2 :   }
+      11             : 
+      12             : 
+      13           5 :   TimeoutManager::timeout_id_t TimeoutManager::registerNew(const ros::Duration& timeout, const callback_t& callback, const ros::Time& last_reset, const bool oneshot, const bool autostart)
+      14             :   {
+      15          10 :     std::scoped_lock lck(m_mtx);
+      16           5 :     const auto new_id = m_timeouts.size();
+      17           5 :     const timeout_info_t new_info = {oneshot, autostart, callback, timeout, last_reset, last_reset};
+      18           5 :     m_timeouts.push_back(new_info);
+      19          10 :     return new_id;
+      20             :   }
+      21             : 
+      22         808 :   void TimeoutManager::reset(const timeout_id_t id, const ros::Time& time)
+      23             :   {
+      24         808 :     std::scoped_lock lck(m_mtx);
+      25         808 :     m_timeouts.at(id).last_reset = time;
+      26         808 :   }
+      27             : 
+      28           9 :   void TimeoutManager::pause(const timeout_id_t id)
+      29             :   {
+      30           9 :     std::scoped_lock lck(m_mtx);
+      31           9 :     m_timeouts.at(id).started = false;
+      32           9 :   }
+      33             : 
+      34           5 :   void TimeoutManager::start(const timeout_id_t id, const ros::Time& time)
+      35             :   {
+      36           5 :     std::scoped_lock lck(m_mtx);
+      37           5 :     m_timeouts.at(id).started = true;
+      38           5 :     m_timeouts.at(id).last_reset = time;
+      39           5 :   }
+      40             : 
+      41           2 :   void TimeoutManager::pauseAll()
+      42             :   {
+      43           4 :     std::scoped_lock lck(m_mtx);
+      44          10 :     for (auto& timeout_info : m_timeouts)
+      45           8 :       timeout_info.started = false;
+      46           2 :   }
+      47             : 
+      48           4 :   void TimeoutManager::startAll(const ros::Time& time)
+      49             :   {
+      50           8 :     std::scoped_lock lck(m_mtx);
+      51          20 :     for (auto& timeout_info : m_timeouts)
+      52             :     {
+      53          16 :       timeout_info.started = true;
+      54          16 :       timeout_info.last_reset = time;
+      55             :     }
+      56           4 :   }
+      57             : 
+      58           0 :   void TimeoutManager::change(const timeout_id_t id, const ros::Duration& timeout, const callback_t& callback, const ros::Time& last_reset, const bool oneshot, const bool autostart)
+      59             :   {
+      60           0 :     std::scoped_lock lck(m_mtx);
+      61           0 :     auto& timeout_info = m_timeouts.at(id);
+      62           0 :     timeout_info.oneshot = oneshot;
+      63           0 :     timeout_info.started = autostart;
+      64           0 :     timeout_info.timeout = timeout;
+      65           0 :     timeout_info.callback = callback;
+      66           0 :     timeout_info.last_reset = last_reset;
+      67           0 :   }
+      68             : 
+      69           0 :   ros::Time TimeoutManager::lastReset(const timeout_id_t id)
+      70             :   {
+      71           0 :     std::scoped_lock lck(m_mtx);
+      72           0 :     return m_timeouts.at(id).last_reset;
+      73             :   }
+      74             : 
+      75        1588 :   bool TimeoutManager::started(const timeout_id_t id)
+      76             :   {
+      77        1588 :     std::scoped_lock lck(m_mtx);
+      78        3176 :     return m_timeouts.at(id).started;
+      79             :   }
+      80             : 
+      81        2098 :   void TimeoutManager::main_timer_callback([[maybe_unused]] const ros::TimerEvent &evt)
+      82             :   {
+      83        2098 :     const auto now = ros::Time::now();
+      84             : 
+      85        4196 :     std::scoped_lock lck(m_mtx);
+      86       10478 :     for (auto& timeout_info : m_timeouts)
+      87             :     {
+      88             :       // don't worry, this'll get optimized out by the compiler
+      89        8380 :       const bool started = timeout_info.started;
+      90        8380 :       const bool last_reset_timeout = now - timeout_info.last_reset >= timeout_info.timeout;
+      91        8380 :       const bool last_callback_timeout = now - timeout_info.last_callback >= timeout_info.timeout;
+      92        8380 :       if (started && last_reset_timeout && last_callback_timeout)
+      93             :       {
+      94        1584 :         timeout_info.callback(timeout_info.last_reset);
+      95        1584 :         timeout_info.last_callback = now;
+      96             :         // if the timeout is oneshot, pause it
+      97        1584 :         if (timeout_info.oneshot)
+      98           0 :           timeout_info.started = false;
+      99             :       }
+     100             :     }
+     101        2098 :   }
+     102             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timer/index-sort-f.html b/mrs_lib/src/timer/index-sort-f.html new file mode 100644 index 0000000000..4397bd901a --- /dev/null +++ b/mrs_lib/src/timer/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timer + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timerHitTotalCoverage
Test:coverage.infoLines:10511492.1 %
Date:2023-11-29 14:09:54Functions:1515100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
timer.cpp +
92.1%92.1%
+
92.1 %105 / 114100.0 %15 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timer/index-sort-l.html b/mrs_lib/src/timer/index-sort-l.html new file mode 100644 index 0000000000..deae1e759c --- /dev/null +++ b/mrs_lib/src/timer/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timer + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timerHitTotalCoverage
Test:coverage.infoLines:10511492.1 %
Date:2023-11-29 14:09:54Functions:1515100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
timer.cpp +
92.1%92.1%
+
92.1 %105 / 114100.0 %15 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timer/index.html b/mrs_lib/src/timer/index.html new file mode 100644 index 0000000000..8b1a27ff09 --- /dev/null +++ b/mrs_lib/src/timer/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timer + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timerHitTotalCoverage
Test:coverage.infoLines:10511492.1 %
Date:2023-11-29 14:09:54Functions:1515100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
timer.cpp +
92.1%92.1%
+
92.1 %105 / 114100.0 %15 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timer/timer.cpp.func-sort-c.html b/mrs_lib/src/timer/timer.cpp.func-sort-c.html new file mode 100644 index 0000000000..b8e025e8f8 --- /dev/null +++ b/mrs_lib/src/timer/timer.cpp.func-sort-c.html @@ -0,0 +1,132 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timer/timer.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timer - timer.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:10511492.1 %
Date:2023-11-29 14:09:54Functions:1515100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11ThreadTimer4Impl9setPeriodERKN3ros8DurationEb8
_ZN7mrs_lib11ThreadTimer4Impl9threadFcnEv8
_ZN7mrs_lib11ThreadTimer4ImplC2ERKSt8functionIFvRKN3ros10TimerEventEEERKNS3_8DurationEb8
_ZN7mrs_lib11ThreadTimer4ImplD2Ev8
_ZN7mrs_lib11ThreadTimer9setPeriodERKN3ros8DurationEb8
_ZN7mrs_lib8ROSTimer9setPeriodERKN3ros8DurationEb8
_ZN7mrs_lib11ThreadTimer4Impl4stopEv24
_ZN7mrs_lib11ThreadTimer4Impl5startEv24
_ZN7mrs_lib11ThreadTimer4stopEv24
_ZN7mrs_lib11ThreadTimer5startEv24
_ZN7mrs_lib8ROSTimer4stopEv24
_ZN7mrs_lib8ROSTimer5startEv24
_ZN7mrs_lib11ThreadTimer4Impl14breakableSleepERKN3ros4TimeE208
_ZN7mrs_lib11ThreadTimer7runningEv208
_ZN7mrs_lib8ROSTimer7runningEv215
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timer/timer.cpp.func.html b/mrs_lib/src/timer/timer.cpp.func.html new file mode 100644 index 0000000000..ab95afc2b2 --- /dev/null +++ b/mrs_lib/src/timer/timer.cpp.func.html @@ -0,0 +1,132 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timer/timer.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timer - timer.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:10511492.1 %
Date:2023-11-29 14:09:54Functions:1515100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11ThreadTimer4Impl14breakableSleepERKN3ros4TimeE208
_ZN7mrs_lib11ThreadTimer4Impl4stopEv24
_ZN7mrs_lib11ThreadTimer4Impl5startEv24
_ZN7mrs_lib11ThreadTimer4Impl9setPeriodERKN3ros8DurationEb8
_ZN7mrs_lib11ThreadTimer4Impl9threadFcnEv8
_ZN7mrs_lib11ThreadTimer4ImplC2ERKSt8functionIFvRKN3ros10TimerEventEEERKNS3_8DurationEb8
_ZN7mrs_lib11ThreadTimer4ImplD2Ev8
_ZN7mrs_lib11ThreadTimer4stopEv24
_ZN7mrs_lib11ThreadTimer5startEv24
_ZN7mrs_lib11ThreadTimer7runningEv208
_ZN7mrs_lib11ThreadTimer9setPeriodERKN3ros8DurationEb8
_ZN7mrs_lib8ROSTimer4stopEv24
_ZN7mrs_lib8ROSTimer5startEv24
_ZN7mrs_lib8ROSTimer7runningEv215
_ZN7mrs_lib8ROSTimer9setPeriodERKN3ros8DurationEb8
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/timer/timer.cpp.gcov.html b/mrs_lib/src/timer/timer.cpp.gcov.html new file mode 100644 index 0000000000..3b357f2057 --- /dev/null +++ b/mrs_lib/src/timer/timer.cpp.gcov.html @@ -0,0 +1,331 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/timer/timer.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/timer - timer.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:10511492.1 %
Date:2023-11-29 14:09:54Functions:1515100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_lib/timer.h>
+       2             : 
+       3             : namespace mrs_lib
+       4             : {
+       5             : 
+       6             : // | ------------------------ ROSTimer ------------------------ |
+       7             : 
+       8             : /* stop() //{ */
+       9             : 
+      10          24 : void ROSTimer::stop() {
+      11             : 
+      12          48 :   std::scoped_lock lock(mutex_timer_);
+      13             : 
+      14          24 :   if (timer_) {
+      15          24 :     timer_->stop();
+      16             :   }
+      17          24 : }
+      18             : 
+      19             : //}
+      20             : 
+      21             : /* start() //{ */
+      22             : 
+      23          24 : void ROSTimer::start() {
+      24             : 
+      25          48 :   std::scoped_lock lock(mutex_timer_);
+      26             : 
+      27          24 :   if (timer_) {
+      28          24 :     timer_->start();
+      29             :   }
+      30          24 : }
+      31             : 
+      32             : //}
+      33             : 
+      34             : /* setPeriod() //{ */
+      35             : 
+      36           8 : void ROSTimer::setPeriod(const ros::Duration& duration, const bool reset) {
+      37             : 
+      38          16 :   std::scoped_lock lock(mutex_timer_);
+      39             : 
+      40           8 :   if (timer_) {
+      41           8 :     timer_->setPeriod(duration, reset);
+      42             :   }
+      43           8 : }
+      44             : 
+      45             : //}
+      46             : 
+      47             : /* running() //{ */
+      48             : 
+      49         215 : bool ROSTimer::running()
+      50             : {
+      51         430 :   std::scoped_lock lock(mutex_timer_);
+      52             : 
+      53         215 :   if (timer_)
+      54         215 :     return timer_->hasStarted();
+      55             :   else
+      56           0 :     return false;
+      57             : }
+      58             : 
+      59             : //}
+      60             : 
+      61             : // | ----------------------- ThreadTimer ---------------------- |
+      62             : 
+      63             : /* TheadTimer::start() //{ */
+      64             : 
+      65          24 : void ThreadTimer::start() {
+      66             : 
+      67          24 :   if (impl_) {
+      68          24 :     impl_->start();
+      69             :   }
+      70          24 : }
+      71             : 
+      72             : //}
+      73             : 
+      74             : /* ThreadTimer::stop() //{ */
+      75             : 
+      76          24 : void ThreadTimer::stop() {
+      77             : 
+      78          24 :   if (impl_) {
+      79          24 :     impl_->stop();
+      80             :   }
+      81          24 : }
+      82             : 
+      83             : //}
+      84             : 
+      85             : /* ThreadTimer::setPeriod() //{ */
+      86             : 
+      87           8 : void ThreadTimer::setPeriod(const ros::Duration& duration, [[maybe_unused]] const bool reset) {
+      88             : 
+      89           8 :   if (impl_) {
+      90           8 :     impl_->setPeriod(duration, reset);
+      91             :   }
+      92           8 : }
+      93             : 
+      94             : //}
+      95             : 
+      96             : /* ThreadTimer::running() //{ */
+      97             : 
+      98         208 : bool ThreadTimer::running()
+      99             : {
+     100         208 :   if (impl_)
+     101         208 :     return impl_->running_;
+     102             :   else
+     103           0 :     return false;
+     104             : }
+     105             : 
+     106             : //}
+     107             : 
+     108             : /* ThreadTimer::Impl //{ */
+     109             : 
+     110           8 : ThreadTimer::Impl::Impl(const std::function<void(const ros::TimerEvent&)>& callback, const ros::Duration& delay_dur, const bool oneshot)
+     111           8 :   : callback_(callback), oneshot_(oneshot), delay_dur_(delay_dur)
+     112             : {
+     113           8 :   ending_  = false;
+     114           8 :   running_ = false;
+     115             : 
+     116           8 :   last_real_     = ros::Time(0);
+     117           8 :   last_expected_ = ros::Time(0);
+     118           8 :   next_expected_ = ros::Time(0);
+     119             : 
+     120           8 :   thread_ = std::thread(&ThreadTimer::Impl::threadFcn, this);
+     121           8 : }
+     122             : 
+     123           8 : ThreadTimer::Impl::~Impl()
+     124             : {
+     125             :   {
+     126             :     // signal the thread to end
+     127          16 :     std::scoped_lock lck(mutex_wakeup_, mutex_state_);
+     128           8 :     ending_ = true;
+     129           8 :     wakeup_cond_.notify_all();
+     130             :   }
+     131             :   // wait for it to die
+     132           8 :   thread_.join();
+     133           8 : }
+     134             : 
+     135          24 : void ThreadTimer::Impl::start()
+     136             : {
+     137          48 :   std::scoped_lock lck(mutex_wakeup_, mutex_state_);
+     138          24 :   if (!running_)
+     139             :   {
+     140          24 :     next_expected_ = ros::Time::now() + delay_dur_;
+     141          24 :     running_ = true;
+     142          24 :     wakeup_cond_.notify_all();
+     143             :   }
+     144          24 : }
+     145             : 
+     146          24 : void ThreadTimer::Impl::stop()
+     147             : {
+     148          48 :   std::scoped_lock lck(mutex_wakeup_, mutex_state_);
+     149          24 :   running_ = false;
+     150          24 :   wakeup_cond_.notify_all();
+     151          24 : }
+     152             : 
+     153           8 : void ThreadTimer::Impl::setPeriod(const ros::Duration& duration, [[maybe_unused]] const bool reset)
+     154             : {
+     155          16 :   std::scoped_lock lock(mutex_wakeup_, mutex_state_);
+     156           8 :   delay_dur_ = duration;
+     157             :   // gracefully handle the special case
+     158           8 :   if (duration == ros::Duration(0))
+     159           0 :     this->oneshot_  = true;
+     160           8 : }
+     161             : 
+     162             : //}
+     163             : 
+     164             : /* ThreadTimer::breakableSleep() method //{ */
+     165         408 : bool ThreadTimer::Impl::breakableSleep(const ros::Time& until)
+     166             : {
+     167         408 :   while (ros::ok() && ros::Time::now() < until)
+     168             :   {
+     169         208 :     const std::chrono::nanoseconds dur {(until - ros::Time::now()).toNSec()};
+     170         208 :     const std::chrono::time_point<std::chrono::steady_clock> until_stl = std::chrono::steady_clock::now() + dur;
+     171         208 :     std::unique_lock lck(mutex_wakeup_);
+     172         208 :     if (!ending_ && running_)
+     173         208 :       wakeup_cond_.wait_until(lck, until_stl);
+     174             :     // check the flags while mutex_state_ is locked
+     175         208 :     if (ending_ || !running_)
+     176           8 :       return false;
+     177             :   }
+     178         200 :   return true;
+     179             : }
+     180             : //}
+     181             : 
+     182             : /* ThreadTimer::Impl::threadFcn() //{ */
+     183             : 
+     184         216 : void ThreadTimer::Impl::threadFcn()
+     185             : {
+     186         216 :   while (ros::ok() && !ending_)
+     187             :   {
+     188             :     {
+     189         216 :       std::unique_lock lck(mutex_wakeup_);
+     190             :       // if the timer is not yet started, wait for condition variable notification
+     191         216 :       if (!running_ && !ending_)
+     192          16 :         wakeup_cond_.wait(lck);
+     193             :       // The thread either got cv-notified, or running_ was already true, or it got woken up for some other reason.
+     194             :       // Check if the reason is that we should end (and end if it is).
+     195         216 :       if (ending_)
+     196           8 :         break;
+     197             :       // Check if the timer is still paused - probably was a spurious wake up (and restart the wait if it is).
+     198         208 :       if (!running_)
+     199           0 :         continue;
+     200             :     }
+     201             : 
+     202             :     // If the flow got here, the thread should attempt to wait for the specified duration.
+     203             :     // first, copy the delay we should wait for in a thread-safe manner
+     204         208 :     ros::Time next_expected;
+     205             :     {
+     206         208 :       std::scoped_lock lck(mutex_state_);
+     207         208 :       next_expected = next_expected_;
+     208             :     }
+     209         208 :     const bool interrupted = !breakableSleep(next_expected);
+     210         208 :     if (interrupted)
+     211           8 :       continue;
+     212             : 
+     213             :     {
+     214             :       // make sure the state doesn't change here
+     215         200 :       std::scoped_lock lck(mutex_state_);
+     216             :       // Again, check if everything is OK (the state may have changed while the thread was a sleeping beauty).
+     217             :       // Check if we should end (and end if it is so).
+     218         200 :       if (ending_)
+     219           0 :         break;
+     220             :       // Check if the timer is paused (and skip if it is so).
+     221         200 :       if (!running_)
+     222           0 :         continue;
+     223             : 
+     224             :       // If all is fine and dandy, actually run the callback function!
+     225             :       // if the timer is a oneshot-type, automatically pause it
+     226             :       // and do not fill out the expected fields in timer_event (we had no expectations...)
+     227         200 :       const ros::Time now = ros::Time::now();
+     228             :       // prepare the timer event
+     229         200 :       ros::TimerEvent timer_event;
+     230         200 :       if (oneshot_)
+     231             :       {
+     232           0 :         running_ = false;
+     233           0 :         timer_event.last_real        = last_real_;
+     234           0 :         timer_event.current_real     = now;
+     235             :       }
+     236             :       else
+     237             :       {
+     238         200 :         timer_event.last_expected    = last_expected_;
+     239         200 :         timer_event.last_real        = last_real_;
+     240         200 :         timer_event.current_expected = next_expected_;
+     241         200 :         timer_event.current_real     = now;
+     242             : 
+     243         200 :         last_expected_ = next_expected_;
+     244         200 :         next_expected_ = now + delay_dur_;
+     245             :       }
+     246         200 :       last_real_ = now;
+     247             :       // call the callback
+     248         200 :       callback_(timer_event);
+     249             :     }
+     250             :   }
+     251           8 : }
+     252             : 
+     253             : //}
+     254             : 
+     255             : }  // namespace mrs_lib
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/transformer/index-sort-f.html b/mrs_lib/src/transformer/index-sort-f.html new file mode 100644 index 0000000000..d2126e17b8 --- /dev/null +++ b/mrs_lib/src/transformer/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/transformer + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/transformerHitTotalCoverage
Test:coverage.infoLines:16528058.9 %
Date:2023-11-29 14:09:54Functions:172665.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
transformer.cpp +
58.9%58.9%
+
58.9 %165 / 28065.4 %17 / 26
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/transformer/index-sort-l.html b/mrs_lib/src/transformer/index-sort-l.html new file mode 100644 index 0000000000..773ff2f1be --- /dev/null +++ b/mrs_lib/src/transformer/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/transformer + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/transformerHitTotalCoverage
Test:coverage.infoLines:16528058.9 %
Date:2023-11-29 14:09:54Functions:172665.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
transformer.cpp +
58.9%58.9%
+
58.9 %165 / 28065.4 %17 / 26
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/transformer/index.html b/mrs_lib/src/transformer/index.html new file mode 100644 index 0000000000..4163c532cc --- /dev/null +++ b/mrs_lib/src/transformer/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/transformer + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/transformerHitTotalCoverage
Test:coverage.infoLines:16528058.9 %
Date:2023-11-29 14:09:54Functions:172665.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
transformer.cpp +
58.9%58.9%
+
58.9 %165 / 28065.4 %17 / 26
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/transformer/transformer.cpp.func-sort-c.html b/mrs_lib/src/transformer/transformer.cpp.func-sort-c.html new file mode 100644 index 0000000000..349c288b3a --- /dev/null +++ b/mrs_lib/src/transformer/transformer.cpp.func-sort-c.html @@ -0,0 +1,176 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/transformer/transformer.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/transformer - transformer.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:16528058.9 %
Date:2023-11-29 14:09:54Functions:172665.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs12PoseStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs13PointStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs5Pose_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs12PoseStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs13PointStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs5Pose_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11TransformerC2ERKN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS1_8DurationE0
_ZN7mrs_lib11TransformerC2Ev0
_ZN7mrs_lib11TransformeraSEOS0_0
_ZN3tf211doTransformIN2cv7Point3_IdEEEEvRKT_RS4_RKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer12getTransformERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeES8_SC_S8_1
_ZN7mrs_lib11Transformer16getTransformImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeES8_SC_S8_S8_1
_ZN7mrs_lib11Transformer9setLatLonEdd1
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs6Point_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs6Point_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib11Transformer13transformImplERKN13geometry_msgs17TransformStamped_ISaIvEEERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE6
_ZN7mrs_lib11Transformer13transformImplERKN13geometry_msgs17TransformStamped_ISaIvEEERKN8mrs_msgs17ReferenceStamped_IS3_EE6
_ZN7mrs_lib11Transformer16transformAsPointERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEERKN13geometry_msgs17TransformStamped_ISaIvEEE6
_ZN7mrs_lib11Transformer16transformAsPointERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES8_RKN3ros4TimeE6
_ZN7mrs_lib11Transformer17transformAsVectorERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEERKN13geometry_msgs17TransformStamped_ISaIvEEE6
_ZN7mrs_lib11Transformer17transformAsVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES8_RKN3ros4TimeE6
_ZN7mrs_lib11Transformer14getFramePrefixERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE10
_ZN7mrs_lib11TransformerC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros8DurationE12
_ZN7mrs_lib11Transformer12getTransformERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_RKN3ros4TimeE51
_ZN7mrs_lib11Transformer16getTransformImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_RKN3ros4TimeES8_71
_ZN7mrs_lib11Transformer16resolveFrameImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE321
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/transformer/transformer.cpp.func.html b/mrs_lib/src/transformer/transformer.cpp.func.html new file mode 100644 index 0000000000..6c96ee403e --- /dev/null +++ b/mrs_lib/src/transformer/transformer.cpp.func.html @@ -0,0 +1,176 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/transformer/transformer.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/transformer - transformer.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:16528058.9 %
Date:2023-11-29 14:09:54Functions:172665.4 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN3tf211doTransformIN2cv7Point3_IdEEEEvRKT_RS4_RKN13geometry_msgs17TransformStamped_ISaIvEEE1
_ZN7mrs_lib11Transformer12getTransformERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeES8_SC_S8_1
_ZN7mrs_lib11Transformer12getTransformERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_RKN3ros4TimeE51
_ZN7mrs_lib11Transformer13transformImplERKN13geometry_msgs17TransformStamped_ISaIvEEERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEE6
_ZN7mrs_lib11Transformer13transformImplERKN13geometry_msgs17TransformStamped_ISaIvEEERKN8mrs_msgs17ReferenceStamped_IS3_EE6
_ZN7mrs_lib11Transformer14getFramePrefixERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE10
_ZN7mrs_lib11Transformer16getTransformImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros4TimeES8_SC_S8_S8_1
_ZN7mrs_lib11Transformer16getTransformImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_RKN3ros4TimeES8_71
_ZN7mrs_lib11Transformer16resolveFrameImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE321
_ZN7mrs_lib11Transformer16transformAsPointERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEERKN13geometry_msgs17TransformStamped_ISaIvEEE6
_ZN7mrs_lib11Transformer16transformAsPointERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES8_RKN3ros4TimeE6
_ZN7mrs_lib11Transformer17transformAsVectorERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEERKN13geometry_msgs17TransformStamped_ISaIvEEE6
_ZN7mrs_lib11Transformer17transformAsVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN5Eigen6MatrixIdLi3ELi1ELi0ELi3ELi1EEES8_RKN3ros4TimeE6
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs12PoseStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs13PointStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs5Pose_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7LLtoUTMERKN13geometry_msgs6Point_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs12PoseStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs13PointStamped_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs5Pose_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN7mrs_lib11Transformer7UTMtoLLERKN13geometry_msgs6Point_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE2
_ZN7mrs_lib11Transformer9setLatLonEdd1
_ZN7mrs_lib11TransformerC2ERKN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS1_8DurationE0
_ZN7mrs_lib11TransformerC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN3ros8DurationE12
_ZN7mrs_lib11TransformerC2Ev0
_ZN7mrs_lib11TransformeraSEOS0_0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/transformer/transformer.cpp.gcov.html b/mrs_lib/src/transformer/transformer.cpp.gcov.html new file mode 100644 index 0000000000..473e6d4b53 --- /dev/null +++ b/mrs_lib/src/transformer/transformer.cpp.gcov.html @@ -0,0 +1,663 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/transformer/transformer.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/transformer - transformer.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:16528058.9 %
Date:2023-11-29 14:09:54Functions:172665.4 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : // clang: MatousFormat
+       2             : 
+       3             : #include <mrs_lib/transformer.h>
+       4             : #include <mrs_lib/gps_conversions.h>
+       5             : #include <opencv2/core/types.hpp>
+       6             : #include <mrs_lib/geometry/conversions.h>
+       7             : #include <mutex>
+       8             : 
+       9             : using test_t = mrs_msgs::ReferenceStamped;
+      10             : /* using test_t = pcl::PointCloud<pcl::PointXYZ>; */
+      11             : template std::optional<test_t> mrs_lib::Transformer::transform<test_t>(const test_t& what, const geometry_msgs::TransformStamped& to_frame);
+      12             : template std::optional<test_t::Ptr> mrs_lib::Transformer::transform<test_t>(const test_t::Ptr& what, const geometry_msgs::TransformStamped& to_frame);
+      13             : template std::optional<test_t::Ptr> mrs_lib::Transformer::transform<test_t>(const test_t::ConstPtr& what, const geometry_msgs::TransformStamped& to_frame);
+      14             : template std::optional<test_t> mrs_lib::Transformer::transformSingle<test_t>(const test_t& what, const std::string& to_frame);
+      15             : template std::optional<test_t::Ptr> mrs_lib::Transformer::transformSingle<test_t>(const test_t::Ptr& what, const std::string& to_frame);
+      16             : template std::optional<test_t::Ptr> mrs_lib::Transformer::transformSingle<test_t>(const test_t::ConstPtr& what, const std::string& to_frame);
+      17             : 
+      18             : namespace tf2
+      19             : {
+      20             :   template <>
+      21           1 :   void doTransform(const cv::Point3d& point_in, cv::Point3d& point_out, const geometry_msgs::TransformStamped& transform)
+      22             :   {
+      23           1 :     const geometry_msgs::Point pt = mrs_lib::geometry::fromCV(point_in);
+      24           1 :     geometry_msgs::Point pt_tfd;
+      25           1 :     tf2::doTransform(pt, pt_tfd, transform);
+      26           1 :     point_out = mrs_lib::geometry::toCV(pt_tfd);
+      27           1 :   }
+      28             : }
+      29             : 
+      30             : namespace mrs_lib
+      31             : {
+      32             : 
+      33             :   // | ----------------------- Transformer ---------------------- |
+      34             : 
+      35             :   // | ------------------ user-callable methods ----------------- |
+      36             : 
+      37             :   /* Transformer() (constructors)//{ */
+      38             : 
+      39           0 :   Transformer::Transformer()
+      40             :   {
+      41           0 :   }
+      42             : 
+      43          12 :   Transformer::Transformer(const std::string& node_name, const ros::Duration& cache_time)
+      44          12 :     : initialized_(true), node_name_(node_name), tf_buffer_(std::make_unique<tf2_ros::Buffer>(cache_time)), tf_listener_ptr_(std::make_unique<tf2_ros::TransformListener>(*tf_buffer_))
+      45             :   {
+      46          12 :   }
+      47             : 
+      48           0 :   Transformer::Transformer(const ros::NodeHandle& nh, const std::string& node_name, const ros::Duration& cache_time)
+      49           0 :     : initialized_(true), node_name_(node_name), tf_buffer_(std::make_unique<tf2_ros::Buffer>(cache_time)), tf_listener_ptr_(std::make_unique<tf2_ros::TransformListener>(*tf_buffer_, nh))
+      50             :   {
+      51           0 :   }
+      52             : 
+      53           0 :   Transformer& Transformer::operator=(Transformer&& other)
+      54             :   {
+      55           0 :     std::scoped_lock lck(other.mutex_, mutex_);
+      56             : 
+      57           0 :     initialized_ = std::move(other.initialized_);
+      58           0 :     node_name_ = std::move(other.node_name_);
+      59           0 :     tf_buffer_ = std::move(other.tf_buffer_);
+      60           0 :     tf_listener_ptr_ = std::move(other.tf_listener_ptr_);
+      61             : 
+      62           0 :     default_frame_id_ = std::move(other.default_frame_id_);
+      63           0 :     prefix_ = std::move(other.prefix_);
+      64           0 :     quiet_ = std::move(other.quiet_);
+      65           0 :     lookup_timeout_ = std::move(other.lookup_timeout_);
+      66           0 :     retry_lookup_newest_ = std::move(other.retry_lookup_newest_);
+      67             : 
+      68           0 :     got_utm_zone_ = std::move(other.got_utm_zone_);
+      69           0 :     utm_zone_ = std::move(other.utm_zone_);
+      70             : 
+      71           0 :     return *this;
+      72             :   }
+      73             : 
+      74             :   //}
+      75             : 
+      76             :   /* getTransform() //{ */
+      77             : 
+      78          51 :   std::optional<geometry_msgs::TransformStamped> Transformer::getTransform(const std::string& from_frame_raw, const std::string& to_frame_raw, const ros::Time& time_stamp)
+      79             :   {
+      80         102 :     std::scoped_lock lck(mutex_);
+      81             : 
+      82          51 :     if (!initialized_)
+      83             :     {
+      84           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot provide transform, not initialized!", node_name_.c_str());
+      85           0 :       return std::nullopt;
+      86             :     }
+      87             : 
+      88             :     // resolve the frames
+      89         102 :     const std::string from_frame = resolveFrameImpl(from_frame_raw);
+      90         102 :     const std::string to_frame = resolveFrameImpl(to_frame_raw);
+      91         102 :     const std::string latlon_frame = resolveFrameImpl(LATLON_ORIGIN);
+      92             : 
+      93          51 :     return getTransformImpl(from_frame, to_frame, time_stamp, latlon_frame);
+      94             :   }
+      95             : 
+      96           1 :   std::optional<geometry_msgs::TransformStamped> Transformer::getTransform(const std::string& from_frame_raw, const ros::Time& from_stamp, const std::string& to_frame_raw, const ros::Time& to_stamp, const std::string& fixed_frame_raw)
+      97             :   {
+      98           2 :     std::scoped_lock lck(mutex_);
+      99             : 
+     100           1 :     if (!initialized_)
+     101             :     {
+     102           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot provide transform, not initialized", node_name_.c_str());
+     103           0 :       return std::nullopt;
+     104             :     }
+     105             : 
+     106           2 :     const std::string from_frame = resolveFrameImpl(from_frame_raw);
+     107           2 :     const std::string to_frame = resolveFrameImpl(to_frame_raw);
+     108           2 :     const std::string fixed_frame = resolveFrameImpl(fixed_frame_raw);
+     109           2 :     const std::string latlon_frame = resolveFrameImpl(LATLON_ORIGIN);
+     110             : 
+     111           1 :     return getTransformImpl(from_frame, from_stamp, to_frame, to_stamp, fixed_frame, latlon_frame);
+     112             :   }
+     113             :   //}
+     114             : 
+     115             :   /* setLatLon() //{ */
+     116             : 
+     117           1 :   void Transformer::setLatLon(const double lat, const double lon)
+     118             :   {
+     119           1 :     std::scoped_lock lck(mutex_);
+     120             : 
+     121             :     double utm_x, utm_y;
+     122           1 :     mrs_lib::LLtoUTM(lat, lon, utm_y, utm_x, utm_zone_.data());
+     123           1 :     got_utm_zone_ = true;
+     124           1 :   }
+     125             : 
+     126             :   //}
+     127             : 
+     128             :   /* transformAsVector() //{ */
+     129             : 
+     130           6 :   [[nodiscard]] std::optional<Eigen::Vector3d> Transformer::transformAsVector(const Eigen::Vector3d& what, const geometry_msgs::TransformStamped& tf)
+     131             :   {
+     132          12 :     std::scoped_lock lck(mutex_);
+     133             : 
+     134           6 :     if (!initialized_)
+     135             :     {
+     136           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot transform, not initialized", node_name_.c_str());
+     137           0 :       return std::nullopt;
+     138             :     }
+     139             : 
+     140          12 :     const std::string from_frame = resolveFrameImpl(frame_from(tf));
+     141          12 :     const std::string to_frame = resolveFrameImpl(frame_to(tf));
+     142          12 :     const geometry_msgs::TransformStamped tf_resolved = create_transform(from_frame, to_frame, tf.header.stamp, tf.transform);
+     143             : 
+     144           6 :     const geometry_msgs::Vector3 vec = mrs_lib::geometry::fromEigenVec(what);
+     145           6 :     const auto tfd_vec = transformImpl(tf_resolved, vec);
+     146           6 :     if (tfd_vec.has_value())
+     147          12 :       return mrs_lib::geometry::toEigen(tfd_vec.value());
+     148             :     else
+     149           0 :       return std::nullopt;
+     150             :   }
+     151             : 
+     152           6 :   [[nodiscard]] std::optional<Eigen::Vector3d> Transformer::transformAsVector(const std::string& from_frame_raw, const Eigen::Vector3d& what, const std::string& to_frame_raw, const ros::Time& time_stamp)
+     153             :   {
+     154          12 :     std::scoped_lock lck(mutex_);
+     155             : 
+     156           6 :     if (!initialized_)
+     157             :     {
+     158           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot transform, not initialized", node_name_.c_str());
+     159           0 :       return std::nullopt;
+     160             :     }
+     161             : 
+     162          12 :     const std::string from_frame = resolveFrameImpl(from_frame_raw);
+     163          12 :     const std::string to_frame = resolveFrameImpl(to_frame_raw);
+     164          12 :     const std::string latlon_frame = resolveFrameImpl(LATLON_ORIGIN);
+     165             : 
+     166             :     // get the transform
+     167          12 :     const auto tf_opt = getTransformImpl(from_frame, to_frame, time_stamp, latlon_frame);
+     168           6 :     if (!tf_opt.has_value())
+     169           0 :       return std::nullopt;
+     170           6 :     const geometry_msgs::TransformStamped& tf = tf_opt.value();
+     171             : 
+     172             :     // do the transformation
+     173          12 :     const geometry_msgs::TransformStamped tf_resolved = create_transform(from_frame, to_frame, tf.header.stamp, tf.transform);
+     174           6 :     const geometry_msgs::Vector3 vec = mrs_lib::geometry::fromEigenVec(what);
+     175           6 :     const auto tfd_vec = transformImpl(tf_resolved, vec);
+     176           6 :     if (tfd_vec.has_value())
+     177          12 :       return mrs_lib::geometry::toEigen(tfd_vec.value());
+     178             :     else
+     179           0 :       return std::nullopt;
+     180             :   }
+     181             : 
+     182             :   /* //} */
+     183             : 
+     184             :   /* transformAsPoint() //{ */
+     185             : 
+     186           6 :   [[nodiscard]] std::optional<Eigen::Vector3d> Transformer::transformAsPoint(const Eigen::Vector3d& what, const geometry_msgs::TransformStamped& tf)
+     187             :   {
+     188          12 :     std::scoped_lock lck(mutex_);
+     189             : 
+     190           6 :     if (!initialized_)
+     191             :     {
+     192           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot transform, not initialized", node_name_.c_str());
+     193           0 :       return std::nullopt;
+     194             :     }
+     195             : 
+     196          12 :     const std::string from_frame = resolveFrameImpl(frame_from(tf));
+     197          12 :     const std::string to_frame = resolveFrameImpl(frame_to(tf));
+     198          12 :     const geometry_msgs::TransformStamped tf_resolved = create_transform(from_frame, to_frame, tf.header.stamp, tf.transform);
+     199             : 
+     200           6 :     geometry_msgs::Point pt;
+     201           6 :     pt.x = what.x();
+     202           6 :     pt.y = what.y();
+     203           6 :     pt.z = what.z();
+     204           6 :     const auto tfd_pt = transformImpl(tf_resolved, pt);
+     205           6 :     if (tfd_pt.has_value())
+     206          12 :       return mrs_lib::geometry::toEigen(tfd_pt.value());
+     207             :     else
+     208           0 :       return std::nullopt;
+     209             :   }
+     210             : 
+     211           6 :   [[nodiscard]] std::optional<Eigen::Vector3d> Transformer::transformAsPoint(const std::string& from_frame_raw, const Eigen::Vector3d& what, const std::string& to_frame_raw, const ros::Time& time_stamp)
+     212             :   {
+     213          12 :     std::scoped_lock lck(mutex_);
+     214             : 
+     215           6 :     if (!initialized_)
+     216             :     {
+     217           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot transform, not initialized", node_name_.c_str());
+     218           0 :       return std::nullopt;
+     219             :     }
+     220             : 
+     221          12 :     const std::string from_frame = resolveFrameImpl(from_frame_raw);
+     222          12 :     const std::string to_frame = resolveFrameImpl(to_frame_raw);
+     223          12 :     const std::string latlon_frame = resolveFrameImpl(LATLON_ORIGIN);
+     224             : 
+     225             :     // get the transform
+     226          12 :     const auto tf_opt = getTransformImpl(from_frame, to_frame, time_stamp, latlon_frame);
+     227           6 :     if (!tf_opt.has_value())
+     228           0 :       return std::nullopt;
+     229           6 :     const geometry_msgs::TransformStamped& tf = tf_opt.value();
+     230             : 
+     231             :     // do the transformation
+     232          12 :     const geometry_msgs::TransformStamped tf_resolved = create_transform(from_frame, to_frame, tf.header.stamp, tf.transform);
+     233           6 :     geometry_msgs::Point pt;
+     234           6 :     pt.x = what.x();
+     235           6 :     pt.y = what.y();
+     236           6 :     pt.z = what.z();
+     237           6 :     const auto tfd_pt = transformImpl(tf_resolved, pt);
+     238           6 :     if (tfd_pt.has_value())
+     239          12 :       return mrs_lib::geometry::toEigen(tfd_pt.value());
+     240             :     else
+     241           0 :       return std::nullopt;
+     242             :   }
+     243             : 
+     244             :   /* //} */
+     245             : 
+     246             :   // | ------------- helper implementation methods -------------- |
+     247             : 
+     248             :   /* transformImpl() //{ */
+     249             : 
+     250             :   /* specialization for mrs_msgs::ReferenceStamped //{ */
+     251             :   
+     252           6 :   std::optional<mrs_msgs::ReferenceStamped> Transformer::transformImpl(const geometry_msgs::TransformStamped& tf, const mrs_msgs::ReferenceStamped& what)
+     253             :   {
+     254             :     // create a pose message
+     255          12 :     geometry_msgs::PoseStamped pose;
+     256           6 :     pose.header = what.header;
+     257             :   
+     258           6 :     pose.pose.position.x = what.reference.position.x;
+     259           6 :     pose.pose.position.y = what.reference.position.y;
+     260           6 :     pose.pose.position.z = what.reference.position.z;
+     261           6 :     pose.pose.orientation = geometry::fromEigen(geometry::quaternionFromHeading(what.reference.heading));
+     262             :   
+     263             :     // try to transform the pose message
+     264          12 :     const auto pose_opt = transformImpl(tf, pose);
+     265           6 :     if (!pose_opt.has_value())
+     266           0 :       return std::nullopt;
+     267             :     // overwrite the pose with it's transformed value
+     268           6 :     pose = pose_opt.value();
+     269             :   
+     270          12 :     mrs_msgs::ReferenceStamped ret;
+     271           6 :     ret.header = pose.header;
+     272             :   
+     273             :     // copy the new transformed data back
+     274           6 :     ret.reference.position.x = pose.pose.position.x;
+     275           6 :     ret.reference.position.y = pose.pose.position.y;
+     276           6 :     ret.reference.position.z = pose.pose.position.z;
+     277           6 :     ret.reference.heading = geometry::headingFromRot(geometry::toEigen(pose.pose.orientation));
+     278           6 :     return ret;
+     279             :   }
+     280             :   
+     281             :   //}
+     282             : 
+     283             :   /* specialization for Eigen::Vector3d //{ */
+     284             :   
+     285           6 :   std::optional<Eigen::Vector3d> Transformer::transformImpl(const geometry_msgs::TransformStamped& tf, const Eigen::Vector3d& what)
+     286             :   {
+     287             :     // just transform it as you would a geometry_msgs::Vector3
+     288           6 :     const geometry_msgs::Vector3 as_vec = mrs_lib::geometry::fromEigenVec(what);
+     289           6 :     const auto opt = transformImpl(tf, as_vec);
+     290           6 :     if (opt.has_value())
+     291          12 :       return geometry::toEigen(opt.value());
+     292             :     else
+     293           0 :       return std::nullopt;
+     294             :   }
+     295             :   
+     296             :   //}
+     297             : 
+     298             :   //}
+     299             : 
+     300             :   /* getTransformImpl() //{ */
+     301             : 
+     302          71 :   std::optional<geometry_msgs::TransformStamped> Transformer::getTransformImpl(const std::string& from_frame, const std::string& to_frame, const ros::Time& time_stamp, const std::string& latlon_frame)
+     303             :   {
+     304          71 :     if (!initialized_)
+     305             :     {
+     306           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot provide transform, not initialized!", node_name_.c_str());
+     307           0 :       return std::nullopt;
+     308             :     }
+     309             : 
+     310             :     // if any of the frames is empty, then the query is invalid, return nullopt
+     311          71 :     if (from_frame.empty() || to_frame.empty())
+     312             :     {
+     313           3 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot transform to/from an empty frame!", node_name_.c_str());
+     314           3 :       return std::nullopt;
+     315             :     }
+     316             : 
+     317             :     // if the frames are the same, just return an identity transform
+     318          68 :     if (from_frame == to_frame)
+     319           2 :       return create_transform(from_frame, to_frame, time_stamp, tf2::toMsg(tf2::Transform::getIdentity()));
+     320             : 
+     321             :     // check for a transform from/to latlon coordinates - that is a special case handled separately
+     322          67 :     if (from_frame == latlon_frame)
+     323             :     {
+     324             :       // find the transformation between the UTM frame and the non-latlon frame to fill the returned tf
+     325           6 :       const std::string utm_frame = getFramePrefix(from_frame) + "utm_origin";
+     326           6 :       auto tf_opt = getTransformImpl(utm_frame, to_frame, time_stamp, latlon_frame);
+     327           3 :       if (!tf_opt.has_value())
+     328           0 :         return std::nullopt;
+     329             :       // change the transformation frames to point from latlon
+     330           3 :       frame_from(*tf_opt) = from_frame;
+     331           3 :       return tf_opt;
+     332             :     }
+     333          64 :     else if (to_frame == latlon_frame)
+     334             :     {
+     335             :       // find the transformation between the UTM frame and the non-latlon frame to fill the returned tf
+     336           6 :       const std::string utm_frame = getFramePrefix(to_frame) + "utm_origin";
+     337           6 :       auto tf_opt = getTransformImpl(from_frame, utm_frame, time_stamp, latlon_frame);
+     338           3 :       if (!tf_opt.has_value())
+     339           0 :         return std::nullopt;
+     340             :       // change the transformation frames to point to latlon
+     341           3 :       frame_to(*tf_opt) = to_frame;
+     342           3 :       return tf_opt;
+     343             :     }
+     344             : 
+     345         183 :     tf2::TransformException ex("");
+     346             :     // first try to get transform at the requested time
+     347             :     try
+     348             :     {
+     349             :       // try looking up and returning the transform
+     350          91 :       return tf_buffer_->lookupTransform(to_frame, from_frame, time_stamp, lookup_timeout_);
+     351             :     }
+     352          62 :     catch (tf2::TransformException& e)
+     353             :     {
+     354          31 :       ex = e;
+     355             :     }
+     356             : 
+     357             :     // if that failed, try to get the newest one if requested
+     358          31 :     if (retry_lookup_newest_)
+     359             :     {
+     360             :       try
+     361             :       {
+     362           2 :         return tf_buffer_->lookupTransform(to_frame, from_frame, ros::Time(0), lookup_timeout_);
+     363             :       }
+     364           0 :       catch (tf2::TransformException& e)
+     365             :       {
+     366           0 :         ex = e;
+     367             :       }
+     368             :     }
+     369             : 
+     370             :     // if the flow got here, we've failed to look the transform up
+     371          30 :     if (quiet_)
+     372             :     {
+     373           0 :       ROS_DEBUG("[%s]: Transformer: Exception caught while looking up transform from \"%s\" to \"%s\": %s", node_name_.c_str(), from_frame.c_str(),
+     374             :                 to_frame.c_str(), ex.what());
+     375             :     } else
+     376             :     {
+     377          30 :       ROS_WARN_THROTTLE(1.0, "[%s]: Transformer: Exception caught while looking up transform from \"%s\" to \"%s\": %s", node_name_.c_str(),
+     378             :                         from_frame.c_str(), to_frame.c_str(), ex.what());
+     379             :     }
+     380             : 
+     381          30 :     return std::nullopt;
+     382             :   }
+     383             : 
+     384           1 :   std::optional<geometry_msgs::TransformStamped> Transformer::getTransformImpl(const std::string& from_frame, const ros::Time& from_stamp, const std::string& to_frame, const ros::Time& to_stamp, const std::string& fixed_frame, const std::string& latlon_frame)
+     385             :   {
+     386           1 :     if (!initialized_)
+     387             :     {
+     388           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Transformer: cannot provide transform, not initialized", node_name_.c_str());
+     389           0 :       return std::nullopt;
+     390             :     }
+     391             : 
+     392             :     // if the frames are the same, just return an identity transform
+     393           1 :     if (from_frame == to_frame)
+     394           0 :       return create_transform(from_frame, to_frame, to_stamp, tf2::toMsg(tf2::Transform::getIdentity()));
+     395             : 
+     396             :     // check for a transform from/to latlon coordinates - that is a special case handled separately
+     397           1 :     if (from_frame == latlon_frame)
+     398             :     {
+     399             :       // find the transformation between the UTM frame and the non-latlon frame to fill the returned tf
+     400           0 :       const std::string utm_frame = getFramePrefix(from_frame) + "utm_origin";
+     401           0 :       auto tf_opt = getTransformImpl(utm_frame, from_stamp, to_frame, to_stamp, fixed_frame, latlon_frame);
+     402           0 :       if (!tf_opt.has_value())
+     403           0 :         return std::nullopt;
+     404             :       // change the transformation frames to point from latlon
+     405           0 :       frame_from(*tf_opt) = from_frame;
+     406           0 :       return tf_opt;
+     407             :     }
+     408           1 :     else if (to_frame == latlon_frame)
+     409             :     {
+     410             :       // find the transformation between the UTM frame and the non-latlon frame to fill the returned tf
+     411           0 :       const std::string utm_frame = getFramePrefix(to_frame) + "utm_origin";
+     412           0 :       auto tf_opt = getTransformImpl(from_frame, from_stamp, utm_frame, to_stamp, fixed_frame, latlon_frame);
+     413           0 :       if (!tf_opt.has_value())
+     414           0 :         return std::nullopt;
+     415             :       // change the transformation frames to point to latlon
+     416           0 :       frame_to(*tf_opt) = to_frame;
+     417           0 :       return tf_opt;
+     418             :     }
+     419             : 
+     420           3 :     tf2::TransformException ex("");
+     421             :     // first try to get transform at the requested time
+     422             :     try
+     423             :     {
+     424             :       // try looking up and returning the transform
+     425           2 :       return tf_buffer_->lookupTransform(to_frame, to_stamp, from_frame, from_stamp, fixed_frame, lookup_timeout_);
+     426             :     }
+     427           0 :     catch (tf2::TransformException& e)
+     428             :     {
+     429           0 :       ex = e;
+     430             :     }
+     431             : 
+     432             :     // if that failed, try to get the newest one if requested
+     433           0 :     if (retry_lookup_newest_)
+     434             :     {
+     435             :       try
+     436             :       {
+     437           0 :         return tf_buffer_->lookupTransform(to_frame, from_frame, ros::Time(0), lookup_timeout_);
+     438             :       }
+     439           0 :       catch (tf2::TransformException& e)
+     440             :       {
+     441           0 :         ex = e;
+     442             :       }
+     443             :     }
+     444             : 
+     445             :     // if the flow got here, we've failed to look the transform up
+     446           0 :     if (quiet_)
+     447             :     {
+     448           0 :       ROS_DEBUG("[%s]: Transformer: Exception caught while looking up transform from \"%s\" to \"%s\": %s", node_name_.c_str(), from_frame.c_str(),
+     449             :                 to_frame.c_str(), ex.what());
+     450             :     } else
+     451             :     {
+     452           0 :       ROS_WARN_THROTTLE(1.0, "[%s]: Transformer: Exception caught while looking up transform from \"%s\" to \"%s\": %s", node_name_.c_str(),
+     453             :                         from_frame.c_str(), to_frame.c_str(), ex.what());
+     454             :     }
+     455             : 
+     456           0 :     return std::nullopt;
+     457             :   }
+     458             : 
+     459             :   //}
+     460             : 
+     461             :   /* resolveFrameImpl() //{*/
+     462             : 
+     463         321 :   std::string Transformer::resolveFrameImpl(const std::string& frame_id)
+     464             :   {
+     465             :     // if the frame is empty, return the default frame id
+     466         321 :     if (frame_id.empty())
+     467           6 :       return default_frame_id_;
+     468             : 
+     469             :     // if there is no prefix set, just return the raw frame id
+     470         315 :     if (prefix_.empty())
+     471          67 :       return frame_id;
+     472             : 
+     473             :     // if there is a default prefix set and the frame does not start with it, prefix it
+     474         248 :     if (frame_id.substr(0, prefix_.length()) != prefix_)
+     475         145 :       return prefix_ + frame_id;
+     476             : 
+     477         103 :     return frame_id;
+     478             :   }
+     479             : 
+     480             :   //}
+     481             : 
+     482             :   /* LLtoUTM() method //{ */
+     483           2 :   geometry_msgs::Point Transformer::LLtoUTM(const geometry_msgs::Point& what, [[maybe_unused]] const std::string& prefix)
+     484             :   {
+     485             :     // convert LAT-LON to UTM
+     486           2 :     geometry_msgs::Point utm;
+     487           2 :     mrs_lib::UTM(what.x, what.y, &utm.x, &utm.y);
+     488             :     // copy the height from the input
+     489           2 :     utm.z = what.z;
+     490           2 :     return utm;
+     491             :   }
+     492             : 
+     493           0 :   geometry_msgs::PointStamped Transformer::LLtoUTM(const geometry_msgs::PointStamped& what, [[maybe_unused]] const std::string& prefix)
+     494             :   {
+     495           0 :     geometry_msgs::PointStamped ret;
+     496           0 :     ret.header.frame_id = prefix + "utm_origin";
+     497           0 :     ret.header.stamp = what.header.stamp;
+     498           0 :     ret.point = LLtoUTM(what.point, prefix);
+     499           0 :     return ret;
+     500             :   }
+     501             : 
+     502           0 :   geometry_msgs::Pose Transformer::LLtoUTM(const geometry_msgs::Pose& what, const std::string& prefix)
+     503             :   {
+     504           0 :     geometry_msgs::Pose ret;
+     505           0 :     ret.position = LLtoUTM(what.position, prefix);
+     506           0 :     ret.orientation = what.orientation;
+     507           0 :     return ret;
+     508             :   }
+     509             : 
+     510           0 :   geometry_msgs::PoseStamped Transformer::LLtoUTM(const geometry_msgs::PoseStamped& what, const std::string& prefix)
+     511             :   {
+     512           0 :     geometry_msgs::PoseStamped ret;
+     513           0 :     ret.header.frame_id = prefix + "utm_origin";
+     514           0 :     ret.header.stamp = what.header.stamp;
+     515           0 :     ret.pose = LLtoUTM(what.pose, prefix);
+     516           0 :     return ret;
+     517             :   }
+     518             :   //}
+     519             : 
+     520             :   /* UTMtoLL() method //{ */
+     521           2 :   std::optional<geometry_msgs::Point> Transformer::UTMtoLL(const geometry_msgs::Point& what, [[maybe_unused]] const std::string& prefix)
+     522             :   {
+     523             :     // if no UTM zone was specified by the user, we don't know which one to use...
+     524           2 :     if (!got_utm_zone_)
+     525             :     {
+     526           1 :       ROS_WARN_THROTTLE(1.0, "[%s]: cannot transform to latlong, missing UTM zone (did you call setLatLon()?)", node_name_.c_str());
+     527           1 :       return std::nullopt;
+     528             :     }
+     529             :   
+     530             :     // now apply the nonlinear transformation from UTM to LAT-LON
+     531           1 :     geometry_msgs::Point latlon;
+     532           1 :     mrs_lib::UTMtoLL(what.y, what.x, utm_zone_.data(), latlon.x, latlon.y);
+     533           1 :     latlon.z = what.z;
+     534           1 :     return latlon;
+     535             :   }
+     536             : 
+     537           0 :   std::optional<geometry_msgs::PointStamped> Transformer::UTMtoLL(const geometry_msgs::PointStamped& what, [[maybe_unused]] const std::string& prefix)
+     538             :   {
+     539           0 :     const auto opt = UTMtoLL(what.point, prefix);
+     540           0 :     if (!opt.has_value())
+     541           0 :       return std::nullopt;
+     542             : 
+     543           0 :     geometry_msgs::PointStamped ret;
+     544           0 :     ret.header.frame_id = prefix + "utm_origin";
+     545           0 :     ret.header.stamp = what.header.stamp;
+     546           0 :     ret.point = opt.value();
+     547           0 :     return ret;
+     548             :   }
+     549             : 
+     550           0 :   std::optional<geometry_msgs::Pose> Transformer::UTMtoLL(const geometry_msgs::Pose& what, const std::string& prefix)
+     551             :   {
+     552           0 :     const auto opt = UTMtoLL(what.position, prefix);
+     553           0 :     if (!opt.has_value())
+     554           0 :       return std::nullopt;
+     555             : 
+     556           0 :     geometry_msgs::Pose ret;
+     557           0 :     ret.position = opt.value();
+     558           0 :     ret.orientation = what.orientation;
+     559           0 :     return ret;
+     560             :   }
+     561             : 
+     562           0 :   std::optional<geometry_msgs::PoseStamped> Transformer::UTMtoLL(const geometry_msgs::PoseStamped& what, const std::string& prefix)
+     563             :   {
+     564           0 :     const auto opt = UTMtoLL(what.pose, prefix);
+     565           0 :     if (!opt.has_value())
+     566           0 :       return std::nullopt;
+     567             : 
+     568           0 :     geometry_msgs::PoseStamped ret;
+     569           0 :     ret.header.frame_id = prefix + "utm_origin";
+     570           0 :     ret.header.stamp = what.header.stamp;
+     571           0 :     ret.pose = opt.value();
+     572           0 :     return ret;
+     573             :   }
+     574             :   //}
+     575             : 
+     576             :   /* getFramePrefix() method //{ */
+     577          10 :   std::string Transformer::getFramePrefix(const std::string& frame_id)
+     578             :   {
+     579          10 :     const auto firstof = frame_id.find_first_of('/');
+     580          10 :     if (firstof == std::string::npos)
+     581           0 :       return "";
+     582             :     else
+     583          10 :       return frame_id.substr(0, firstof+1);
+     584             :   }
+     585             :   //}
+     586             : 
+     587             : }  // namespace mrs_lib
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/utils/index-sort-f.html b/mrs_lib/src/utils/index-sort-f.html new file mode 100644 index 0000000000..084854f47c --- /dev/null +++ b/mrs_lib/src/utils/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/utils + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/utilsHitTotalCoverage
Test:coverage.infoLines:77100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
utils.cpp +
100.0%
+
100.0 %7 / 7100.0 %2 / 2
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/utils/index-sort-l.html b/mrs_lib/src/utils/index-sort-l.html new file mode 100644 index 0000000000..873669047e --- /dev/null +++ b/mrs_lib/src/utils/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/utils + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/utilsHitTotalCoverage
Test:coverage.infoLines:77100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
utils.cpp +
100.0%
+
100.0 %7 / 7100.0 %2 / 2
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/utils/index.html b/mrs_lib/src/utils/index.html new file mode 100644 index 0000000000..ba3b962f55 --- /dev/null +++ b/mrs_lib/src/utils/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/utils + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/utilsHitTotalCoverage
Test:coverage.infoLines:77100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
utils.cpp +
100.0%
+
100.0 %7 / 7100.0 %2 / 2
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/utils/utils.cpp.func-sort-c.html b/mrs_lib/src/utils/utils.cpp.func-sort-c.html new file mode 100644 index 0000000000..d9c742b0f7 --- /dev/null +++ b/mrs_lib/src/utils/utils.cpp.func-sort-c.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/utils/utils.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/utils - utils.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:77100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib15AtomicScopeFlagC2ERSt6atomicIbE1991
_ZN7mrs_lib15AtomicScopeFlagD2Ev1991
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/utils/utils.cpp.func.html b/mrs_lib/src/utils/utils.cpp.func.html new file mode 100644 index 0000000000..acf0916c35 --- /dev/null +++ b/mrs_lib/src/utils/utils.cpp.func.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/utils/utils.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/utils - utils.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:77100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN7mrs_lib15AtomicScopeFlagC2ERSt6atomicIbE1991
_ZN7mrs_lib15AtomicScopeFlagD2Ev1991
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_lib/src/utils/utils.cpp.gcov.html b/mrs_lib/src/utils/utils.cpp.gcov.html new file mode 100644 index 0000000000..b73a183644 --- /dev/null +++ b/mrs_lib/src/utils/utils.cpp.gcov.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_lib/src/utils/utils.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_lib/src/utils - utils.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:77100.0 %
Date:2023-11-29 14:09:54Functions:22100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_lib/utils.h>
+       2             : 
+       3             : namespace mrs_lib
+       4             : {
+       5             : 
+       6        1991 : AtomicScopeFlag::AtomicScopeFlag(std::atomic<bool>& in)
+       7        1991 :   : variable(in)
+       8             : {
+       9        1991 :   variable = true;
+      10        1991 : }
+      11             : 
+      12        3982 : AtomicScopeFlag::~AtomicScopeFlag()
+      13             : {
+      14        1991 :   variable = false;
+      15        1991 : }
+      16             : 
+      17             : }  // namespace mrs_lib
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/control_manager/index-sort-f.html b/mrs_uav_managers/include/control_manager/index-sort-f.html new file mode 100644 index 0000000000..c0a8e6b35d --- /dev/null +++ b/mrs_uav_managers/include/control_manager/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/control_managerHitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:31030.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
output_publisher.h +
100.0%
+
100.0 %4 / 430.0 %3 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/control_manager/index-sort-l.html b/mrs_uav_managers/include/control_manager/index-sort-l.html new file mode 100644 index 0000000000..e4d7f29274 --- /dev/null +++ b/mrs_uav_managers/include/control_manager/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/control_managerHitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:31030.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
output_publisher.h +
100.0%
+
100.0 %4 / 430.0 %3 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/control_manager/index.html b/mrs_uav_managers/include/control_manager/index.html new file mode 100644 index 0000000000..bc39d88aa3 --- /dev/null +++ b/mrs_uav_managers/include/control_manager/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/control_managerHitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:31030.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
output_publisher.h +
100.0%
+
100.0 %4 / 430.0 %3 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/control_manager/output_publisher.h.func-sort-c.html b/mrs_uav_managers/include/control_manager/output_publisher.h.func-sort-c.html new file mode 100644 index 0000000000..b3f3ab1e7e --- /dev/null +++ b/mrs_uav_managers/include/control_manager/output_publisher.h.func-sort-c.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/control_manager/output_publisher.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/control_manager - output_publisher.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:31030.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs17HwApiActuatorCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs17HwApiPositionCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEEEEvRKT_1435
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEEEEvRKT_5865
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorC2EPS1_7300
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/control_manager/output_publisher.h.func.html b/mrs_uav_managers/include/control_manager/output_publisher.h.func.html new file mode 100644 index 0000000000..1fedd569ed --- /dev/null +++ b/mrs_uav_managers/include/control_manager/output_publisher.h.func.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/control_manager/output_publisher.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/control_manager - output_publisher.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:31030.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorC2EPS1_7300
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs17HwApiActuatorCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEEEEvRKT_1435
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs17HwApiPositionCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEEEEvRKT_5865
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEEEEvRKT_0
_ZN16mrs_uav_managers15control_manager15OutputPublisher16PublisherVisitorclIN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEEEEvRKT_0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/control_manager/output_publisher.h.gcov.html b/mrs_uav_managers/include/control_manager/output_publisher.h.gcov.html new file mode 100644 index 0000000000..0931ac41f2 --- /dev/null +++ b/mrs_uav_managers/include/control_manager/output_publisher.h.gcov.html @@ -0,0 +1,138 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/control_manager/output_publisher.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/control_manager - output_publisher.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:44100.0 %
Date:2023-11-29 14:09:54Functions:31030.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef CONTROL_MANAGER_OUTPUT_PUBLISHER
+       2             : #define CONTROL_MANAGER_OUTPUT_PUBLISHER
+       3             : 
+       4             : #include <mrs_lib/publisher_handler.h>
+       5             : 
+       6             : #include <mrs_uav_managers/controller.h>
+       7             : 
+       8             : namespace mrs_uav_managers
+       9             : {
+      10             : 
+      11             : namespace control_manager
+      12             : {
+      13             : 
+      14             : class OutputPublisher {
+      15             : 
+      16             : public:
+      17             :   OutputPublisher();
+      18             : 
+      19             :   OutputPublisher(ros::NodeHandle& nh);
+      20             : 
+      21             :   void publish(const Controller::HwApiOutputVariant& control_output);
+      22             : 
+      23             : private:
+      24             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiActuatorCmd>            ph_hw_api_actuator_cmd_;
+      25             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiControlGroupCmd>        ph_hw_api_control_group_cmd_;
+      26             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiAttitudeRateCmd>        ph_hw_api_attitude_rate_cmd_;
+      27             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiAttitudeCmd>            ph_hw_api_attitude_cmd_;
+      28             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiAccelerationHdgRateCmd> ph_hw_api_acceleration_hdg_rate_cmd_;
+      29             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiAccelerationHdgCmd>     ph_hw_api_acceleration_hdg_cmd_;
+      30             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiVelocityHdgRateCmd>     ph_hw_api_velocity_hdg_rate_cmd_;
+      31             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiVelocityHdgCmd>         ph_hw_api_velocity_hdg_cmd_;
+      32             :   mrs_lib::PublisherHandler<mrs_msgs::HwApiPositionCmd>            ph_hw_api_position_cmd_;
+      33             : 
+      34             :   void publish(const mrs_msgs::HwApiActuatorCmd& msg);
+      35             :   void publish(const mrs_msgs::HwApiControlGroupCmd& msg);
+      36             :   void publish(const mrs_msgs::HwApiAttitudeRateCmd& msg);
+      37             :   void publish(const mrs_msgs::HwApiAttitudeCmd& msg);
+      38             :   void publish(const mrs_msgs::HwApiAccelerationHdgRateCmd& msg);
+      39             :   void publish(const mrs_msgs::HwApiAccelerationHdgCmd& msg);
+      40             :   void publish(const mrs_msgs::HwApiVelocityHdgRateCmd& msg);
+      41             :   void publish(const mrs_msgs::HwApiVelocityHdgCmd& msg);
+      42             :   void publish(const mrs_msgs::HwApiPositionCmd& msg);
+      43             : 
+      44             :   class PublisherVisitor {
+      45             : 
+      46             :   public:
+      47        7300 :     PublisherVisitor(OutputPublisher* obj) : obj_(obj){};
+      48             : 
+      49             :     OutputPublisher* obj_;
+      50             : 
+      51             :     template <class T>
+      52        7300 :     void operator()(const T& msg) {
+      53        7300 :       obj_->publish(msg);
+      54        7300 :     }
+      55             :   };
+      56             : };
+      57             : 
+      58             : }  // namespace control_manager
+      59             : 
+      60             : }  // namespace mrs_uav_managers
+      61             : 
+      62             : #endif  //  CONTROL_MANAGER_OUTPUT_PUBLISHER
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.func-sort-c.html b/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.func-sort-c.html new file mode 100644 index 0000000000..5c1b307435 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.func-sort-c.html @@ -0,0 +1,180 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/control_manager - common.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:139613.5 %
Date:2023-11-29 14:09:54Functions:52718.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_438
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_1435
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEE2833
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_5428
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEE5894
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.func.html b/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.func.html new file mode 100644 index 0000000000..ff4bff1490 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.func.html @@ -0,0 +1,180 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/control_manager - common.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:139613.5 %
Date:2023-11-29 14:09:54Functions:52718.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_1435
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_5428
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager20HwApiValidateVisitorclERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESI_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_438
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager22HwApiInitializeVisitorclERN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNS2_9UavState_IS4_EERKdSC_0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEE2833
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEE5894
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager30HwApiCmdExtractThrottleVisitorclERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEE0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.gcov.html b/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.gcov.html new file mode 100644 index 0000000000..a6fc251310 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h.gcov.html @@ -0,0 +1,372 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/control_manager/common.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/control_manager - common.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:139613.5 %
Date:2023-11-29 14:09:54Functions:52718.5 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef CONTROL_MANAGER_COMMON_H
+       2             : #define CONTROL_MANAGER_COMMON_H
+       3             : 
+       4             : #include <ros/ros.h>
+       5             : 
+       6             : #include <vector>
+       7             : #include <string>
+       8             : #include <optional>
+       9             : #include <variant>
+      10             : 
+      11             : #include <mrs_lib/attitude_converter.h>
+      12             : #include <mrs_lib/param_loader.h>
+      13             : 
+      14             : #include <mrs_uav_managers/control_manager/common_handlers.h>
+      15             : #include <mrs_uav_managers/controller.h>
+      16             : 
+      17             : #include <mrs_msgs/TrackerCommand.h>
+      18             : #include <mrs_msgs/UavState.h>
+      19             : #include <mrs_msgs/VelocityReference.h>
+      20             : 
+      21             : #include <mrs_msgs/HwApiActuatorCmd.h>
+      22             : #include <mrs_msgs/HwApiControlGroupCmd.h>
+      23             : #include <mrs_msgs/HwApiAttitudeRateCmd.h>
+      24             : #include <mrs_msgs/HwApiAttitudeCmd.h>
+      25             : #include <mrs_msgs/HwApiAccelerationHdgRateCmd.h>
+      26             : #include <mrs_msgs/HwApiAccelerationHdgCmd.h>
+      27             : #include <mrs_msgs/HwApiVelocityHdgRateCmd.h>
+      28             : #include <mrs_msgs/HwApiVelocityHdgCmd.h>
+      29             : #include <mrs_msgs/HwApiPositionCmd.h>
+      30             : 
+      31             : #include <mrs_msgs/HwApiCapabilities.h>
+      32             : 
+      33             : #include <nav_msgs/Odometry.h>
+      34             : 
+      35             : namespace mrs_uav_managers
+      36             : {
+      37             : 
+      38             : namespace control_manager
+      39             : {
+      40             : 
+      41             : enum CONTROL_OUTPUT
+      42             : {
+      43             :   ACTUATORS_CMD,
+      44             :   CONTROL_GROUP,
+      45             :   ATTITUDE_RATE,
+      46             :   ATTITUDE,
+      47             :   ACCELERATION_HDG_RATE,
+      48             :   ACCELERATION_HDG,
+      49             :   VELOCITY_HDG_RATE,
+      50             :   VELOCITY_HDG,
+      51             :   POSITION
+      52             : };
+      53             : 
+      54             : CONTROL_OUTPUT getLowestOuput(const ControlOutputModalities_t& outputs);
+      55             : 
+      56             : CONTROL_OUTPUT getHighestOuput(const ControlOutputModalities_t& outputs);
+      57             : 
+      58             : std::optional<unsigned int> idxInVector(const std::string& str, const std::vector<std::string>& vec);
+      59             : 
+      60             : // checks for invalid values in the result from trackers
+      61             : bool validateTrackerCommand(const std::optional<mrs_msgs::TrackerCommand>& msg, const std::string& node_name, const std::string& var_name);
+      62             : 
+      63             : // checks for invalid messages in/out
+      64             : bool validateOdometry(const nav_msgs::Odometry& msg, const std::string& node_name, const std::string& var_name);
+      65             : bool validateUavState(const mrs_msgs::UavState& msg, const std::string& node_name, const std::string& var_nam);
+      66             : bool validateVelocityReference(const mrs_msgs::VelocityReference& msg, const std::string& node_name, const std::string& var_name);
+      67             : bool validateReference(const mrs_msgs::Reference& msg, const std::string& node_name, const std::string& var_name);
+      68             : 
+      69             : std::optional<DetailedModelParams_t> loadDetailedUavModelParams(ros::NodeHandle& nh, const std::string& node_name, const std::string& platform_config,
+      70             :                                                                 const std::string& custom_config);
+      71             : 
+      72             : // translates the channel values to desired range
+      73             : double RCChannelToRange(double rc_value, double range, double deadband);
+      74             : 
+      75             : /* throttle extraction //{ */
+      76             : 
+      77             : std::optional<double> extractThrottle(const Controller::ControlOutput& control_output);
+      78             : 
+      79             : struct HwApiCmdExtractThrottleVisitor
+      80             : {
+      81           0 :   std::optional<double> operator()(const mrs_msgs::HwApiActuatorCmd& msg) {
+      82             : 
+      83           0 :     if (msg.motors.size() == 0) {
+      84           0 :       return std::nullopt;
+      85             :     }
+      86             : 
+      87           0 :     double throttle = 0;
+      88             : 
+      89           0 :     for (size_t i = 0; i < msg.motors.size(); i++) {
+      90           0 :       throttle += msg.motors[i];
+      91             :     };
+      92             : 
+      93           0 :     throttle /= msg.motors.size();
+      94             : 
+      95           0 :     return throttle;
+      96             :   }
+      97           0 :   std::optional<double> operator()(const mrs_msgs::HwApiControlGroupCmd& msg) {
+      98           0 :     return msg.throttle;
+      99             :   }
+     100        2833 :   std::optional<double> operator()(const mrs_msgs::HwApiAttitudeCmd& msg) {
+     101        2833 :     return msg.throttle;
+     102             :   }
+     103        5894 :   std::optional<double> operator()(const mrs_msgs::HwApiAttitudeRateCmd& msg) {
+     104        5894 :     return msg.throttle;
+     105             :   }
+     106           0 :   std::optional<double> operator()([[maybe_unused]] const mrs_msgs::HwApiAccelerationHdgRateCmd& msg) {
+     107           0 :     return std::nullopt;
+     108             :   }
+     109           0 :   std::optional<double> operator()([[maybe_unused]] const mrs_msgs::HwApiAccelerationHdgCmd& msg) {
+     110           0 :     return std::nullopt;
+     111             :   }
+     112           0 :   std::optional<double> operator()([[maybe_unused]] const mrs_msgs::HwApiVelocityHdgRateCmd& msg) {
+     113           0 :     return std::nullopt;
+     114             :   }
+     115           0 :   std::optional<double> operator()([[maybe_unused]] const mrs_msgs::HwApiVelocityHdgCmd& msg) {
+     116           0 :     return std::nullopt;
+     117             :   }
+     118           0 :   std::optional<double> operator()([[maybe_unused]] const mrs_msgs::HwApiPositionCmd& msg) {
+     119           0 :     return std::nullopt;
+     120             :   }
+     121             : };
+     122             : 
+     123             : //}
+     124             : 
+     125             : /* control output validation //{ */
+     126             : 
+     127             : bool validateControlOutput(const Controller::ControlOutput& control_output, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     128             :                            const std::string& var_name);
+     129             : 
+     130             : // validation of hw api messages
+     131             : bool validateHwApiActuatorCmd(const mrs_msgs::HwApiActuatorCmd& msg, const std::string& node_name, const std::string& var_name);
+     132             : bool validateHwApiControlGroupCmd(const mrs_msgs::HwApiControlGroupCmd& msg, const std::string& node_name, const std::string& var_name);
+     133             : bool validateHwApiAttitudeCmd(const mrs_msgs::HwApiAttitudeCmd& msg, const std::string& node_name, const std::string& var_name);
+     134             : bool validateHwApiAttitudeRateCmd(const mrs_msgs::HwApiAttitudeRateCmd& msg, const std::string& node_name, const std::string& var_name);
+     135             : bool validateHwApiAccelerationHdgRateCmd(const mrs_msgs::HwApiAccelerationHdgRateCmd& msg, const std::string& node_name, const std::string& var_name);
+     136             : bool validateHwApiAccelerationHdgCmd(const mrs_msgs::HwApiAccelerationHdgCmd& msg, const std::string& node_name, const std::string& var_name);
+     137             : bool validateHwApiVelocityHdgRateCmd(const mrs_msgs::HwApiVelocityHdgRateCmd& msg, const std::string& node_name, const std::string& var_name);
+     138             : bool validateHwApiVelocityHdgCmd(const mrs_msgs::HwApiVelocityHdgCmd& msg, const std::string& node_name, const std::string& var_name);
+     139             : bool validateHwApiPositionCmd(const mrs_msgs::HwApiPositionCmd& msg, const std::string& node_name, const std::string& var_name);
+     140             : 
+     141             : struct HwApiValidateVisitor
+     142             : {
+     143           0 :   bool operator()(const mrs_msgs::HwApiActuatorCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     144             :                   const std::string& var_name) {
+     145             : 
+     146           0 :     if (!output_modalities.actuators) {
+     147           0 :       ROS_ERROR("[%s]: The controller returned an output modality (actuator cmd) that is not supported by the hardware API", node_name.c_str());
+     148           0 :       return false;
+     149             :     }
+     150             : 
+     151           0 :     return validateHwApiActuatorCmd(msg, node_name, var_name);
+     152             :   }
+     153           0 :   bool operator()(const mrs_msgs::HwApiControlGroupCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     154             :                   const std::string& var_name) {
+     155             : 
+     156           0 :     if (!output_modalities.control_group) {
+     157           0 :       ROS_ERROR("[%s]: The controller returned an output modality (control group cmd) that is not supported by the hardware API", node_name.c_str());
+     158           0 :       return false;
+     159             :     }
+     160             : 
+     161           0 :     return validateHwApiControlGroupCmd(msg, node_name, var_name);
+     162             :   }
+     163        1435 :   bool operator()(const mrs_msgs::HwApiAttitudeCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     164             :                   const std::string& var_name) {
+     165             : 
+     166        1435 :     if (!output_modalities.attitude) {
+     167           0 :       ROS_ERROR("[%s]: The controller returned an output modality (attitude cmd) that is not supported by the hardware API", node_name.c_str());
+     168           0 :       return false;
+     169             :     }
+     170             : 
+     171        1435 :     return validateHwApiAttitudeCmd(msg, node_name, var_name);
+     172             :   }
+     173        5428 :   bool operator()(const mrs_msgs::HwApiAttitudeRateCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     174             :                   const std::string& var_name) {
+     175             : 
+     176        5428 :     if (!output_modalities.attitude_rate) {
+     177           0 :       ROS_ERROR("[%s]: The controller returned an output modality (attitude rate cmd) that is not supported by the hardware API", node_name.c_str());
+     178           0 :       return false;
+     179             :     }
+     180             : 
+     181        5428 :     return validateHwApiAttitudeRateCmd(msg, node_name, var_name);
+     182             :   }
+     183           0 :   bool operator()(const mrs_msgs::HwApiAccelerationHdgRateCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     184             :                   const std::string& var_name) {
+     185             : 
+     186           0 :     if (!output_modalities.acceleration_hdg_rate) {
+     187           0 :       ROS_ERROR("[%s]: The controller returned an output modality (acceleration+hdg rate cmd) that is not supported by the hardware API", node_name.c_str());
+     188           0 :       return false;
+     189             :     }
+     190             : 
+     191           0 :     return validateHwApiAccelerationHdgRateCmd(msg, node_name, var_name);
+     192             :   }
+     193           0 :   bool operator()(const mrs_msgs::HwApiAccelerationHdgCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     194             :                   const std::string& var_name) {
+     195             : 
+     196           0 :     if (!output_modalities.acceleration_hdg) {
+     197           0 :       ROS_ERROR("[%s]: The controller returned an output modality (acceleration+hdg cmd) that is not supported by the hardware API", node_name.c_str());
+     198           0 :       return false;
+     199             :     }
+     200             : 
+     201           0 :     return validateHwApiAccelerationHdgCmd(msg, node_name, var_name);
+     202             :   }
+     203           0 :   bool operator()(const mrs_msgs::HwApiVelocityHdgRateCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     204             :                   const std::string& var_name) {
+     205             : 
+     206           0 :     if (!output_modalities.velocity_hdg_rate) {
+     207           0 :       ROS_ERROR("[%s]: The controller returned an output modality (velocity+hdg rate cmd) that is not supported by the hardware API", node_name.c_str());
+     208           0 :       return false;
+     209             :     }
+     210             : 
+     211           0 :     return validateHwApiVelocityHdgRateCmd(msg, node_name, var_name);
+     212             :   }
+     213           0 :   bool operator()(const mrs_msgs::HwApiVelocityHdgCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     214             :                   const std::string& var_name) {
+     215             : 
+     216           0 :     if (!output_modalities.velocity_hdg) {
+     217           0 :       ROS_ERROR("[%s]: The controller returned an output modality (velocity+hdg cmd) that is not supported by the hardware API", node_name.c_str());
+     218           0 :       return false;
+     219             :     }
+     220             : 
+     221           0 :     return validateHwApiVelocityHdgCmd(msg, node_name, var_name);
+     222             :   }
+     223           0 :   bool operator()(const mrs_msgs::HwApiPositionCmd& msg, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     224             :                   const std::string& var_name) {
+     225             : 
+     226           0 :     if (!output_modalities.position) {
+     227           0 :       ROS_ERROR("[%s]: The controller returned an output modality (position cmd) that is not supported by the hardware API", node_name.c_str());
+     228           0 :       return false;
+     229             :     }
+     230             : 
+     231           0 :     return validateHwApiPositionCmd(msg, node_name, var_name);
+     232             :   }
+     233             : };
+     234             : 
+     235             : //}
+     236             : 
+     237             : /* control output initialization //{ */
+     238             : 
+     239             : Controller::HwApiOutputVariant initializeDefaultOutput(const ControlOutputModalities_t& possible_outputs, const mrs_msgs::UavState& uav_state,
+     240             :                                                        const double& min_throttle, const double& n_motors);
+     241             : 
+     242             : void initializeHwApiCmd(mrs_msgs::HwApiActuatorCmd& msg, const double& min_throttle, const double& n_motors);
+     243             : void initializeHwApiCmd(mrs_msgs::HwApiControlGroupCmd& msg, const double& min_throttle);
+     244             : void initializeHwApiCmd(mrs_msgs::HwApiAttitudeRateCmd& msg, const double& min_throttle);
+     245             : void initializeHwApiCmd(mrs_msgs::HwApiAttitudeCmd& msg, const mrs_msgs::UavState& uav_state, const double& min_throttle);
+     246             : void initializeHwApiCmd(mrs_msgs::HwApiAccelerationHdgRateCmd& msg, const mrs_msgs::UavState& uav_state);
+     247             : void initializeHwApiCmd(mrs_msgs::HwApiAccelerationHdgCmd& msg, const mrs_msgs::UavState& uav_state);
+     248             : void initializeHwApiCmd(mrs_msgs::HwApiVelocityHdgRateCmd& msg, const mrs_msgs::UavState& uav_state);
+     249             : void initializeHwApiCmd(mrs_msgs::HwApiVelocityHdgCmd& msg, const mrs_msgs::UavState& uav_state);
+     250             : void initializeHwApiCmd(mrs_msgs::HwApiPositionCmd& msg, const mrs_msgs::UavState& uav_state);
+     251             : 
+     252             : struct HwApiInitializeVisitor
+     253             : {
+     254           0 :   void operator()(mrs_msgs::HwApiActuatorCmd& msg, [[maybe_unused]] const mrs_msgs::UavState& uav_state, const double& min_throttle, const double& n_motors) {
+     255           0 :     initializeHwApiCmd(msg, min_throttle, n_motors);
+     256           0 :   }
+     257           0 :   void operator()(mrs_msgs::HwApiControlGroupCmd& msg, [[maybe_unused]] const mrs_msgs::UavState& uav_state, const double& min_throttle,
+     258             :                   [[maybe_unused]] const double& n_motors) {
+     259           0 :     initializeHwApiCmd(msg, min_throttle);
+     260           0 :   }
+     261           0 :   void operator()(mrs_msgs::HwApiAttitudeCmd& msg, const mrs_msgs::UavState& uav_state, const double& min_throttle, [[maybe_unused]] const double& n_motors) {
+     262           0 :     initializeHwApiCmd(msg, uav_state, min_throttle);
+     263           0 :   }
+     264         438 :   void operator()(mrs_msgs::HwApiAttitudeRateCmd& msg, [[maybe_unused]] const mrs_msgs::UavState& uav_state, const double& min_throttle,
+     265             :                   [[maybe_unused]] const double& n_motors) {
+     266         438 :     initializeHwApiCmd(msg, min_throttle);
+     267         438 :   }
+     268           0 :   void operator()(mrs_msgs::HwApiAccelerationHdgRateCmd& msg, const mrs_msgs::UavState& uav_state, [[maybe_unused]] const double& min_throttle,
+     269             :                   [[maybe_unused]] const double& n_motors) {
+     270           0 :     initializeHwApiCmd(msg, uav_state);
+     271           0 :   }
+     272           0 :   void operator()(mrs_msgs::HwApiAccelerationHdgCmd& msg, const mrs_msgs::UavState& uav_state, [[maybe_unused]] const double& min_throttle,
+     273             :                   [[maybe_unused]] const double& n_motors) {
+     274           0 :     initializeHwApiCmd(msg, uav_state);
+     275           0 :   }
+     276           0 :   void operator()(mrs_msgs::HwApiVelocityHdgRateCmd& msg, const mrs_msgs::UavState& uav_state, [[maybe_unused]] const double& min_throttle,
+     277             :                   [[maybe_unused]] const double& n_motors) {
+     278           0 :     initializeHwApiCmd(msg, uav_state);
+     279           0 :   }
+     280           0 :   void operator()(mrs_msgs::HwApiVelocityHdgCmd& msg, const mrs_msgs::UavState& uav_state, [[maybe_unused]] const double& min_throttle,
+     281             :                   [[maybe_unused]] const double& n_motors) {
+     282           0 :     initializeHwApiCmd(msg, uav_state);
+     283           0 :   }
+     284           0 :   void operator()(mrs_msgs::HwApiPositionCmd& msg, const mrs_msgs::UavState& uav_state, [[maybe_unused]] const double& min_throttle,
+     285             :                   [[maybe_unused]] const double& n_motors) {
+     286           0 :     initializeHwApiCmd(msg, uav_state);
+     287           0 :   }
+     288             : };
+     289             : 
+     290             : //}
+     291             : 
+     292             : }  // namespace control_manager
+     293             : 
+     294             : }  // namespace mrs_uav_managers
+     295             : 
+     296             : #endif  // CONTROL_MANAGER_COMMON_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/control_manager/index-sort-f.html b/mrs_uav_managers/include/mrs_uav_managers/control_manager/index-sort-f.html new file mode 100644 index 0000000000..d4f30f6004 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/control_manager/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/control_managerHitTotalCoverage
Test:coverage.infoLines:139613.5 %
Date:2023-11-29 14:09:54Functions:52718.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
common.h +
13.5%13.5%
+
13.5 %13 / 9618.5 %5 / 27
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/control_manager/index-sort-l.html b/mrs_uav_managers/include/mrs_uav_managers/control_manager/index-sort-l.html new file mode 100644 index 0000000000..d30a069aa1 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/control_manager/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/control_managerHitTotalCoverage
Test:coverage.infoLines:139613.5 %
Date:2023-11-29 14:09:54Functions:52718.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
common.h +
13.5%13.5%
+
13.5 %13 / 9618.5 %5 / 27
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/control_manager/index.html b/mrs_uav_managers/include/mrs_uav_managers/control_manager/index.html new file mode 100644 index 0000000000..dc951fb29c --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/control_manager/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/control_managerHitTotalCoverage
Test:coverage.infoLines:139613.5 %
Date:2023-11-29 14:09:54Functions:52718.5 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
common.h +
13.5%13.5%
+
13.5 %13 / 9618.5 %5 / 27
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index-sort-f.html b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index-sort-f.html new file mode 100644 index 0000000000..c3be1a2e51 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/estimation_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/estimation_managerHitTotalCoverage
Test:coverage.infoLines:8510581.0 %
Date:2023-11-29 14:09:54Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
support.h +
81.0%81.0%
+
81.0 %85 / 10586.7 %13 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index-sort-l.html b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index-sort-l.html new file mode 100644 index 0000000000..9700a56601 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/estimation_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/estimation_managerHitTotalCoverage
Test:coverage.infoLines:8510581.0 %
Date:2023-11-29 14:09:54Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
support.h +
81.0%81.0%
+
81.0 %85 / 10586.7 %13 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index.html b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index.html new file mode 100644 index 0000000000..507f3e9123 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/estimation_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/estimation_managerHitTotalCoverage
Test:coverage.infoLines:8510581.0 %
Date:2023-11-29 14:09:54Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
support.h +
81.0%81.0%
+
81.0 %85 / 10586.7 %13 / 15
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.func-sort-c.html b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.func-sort-c.html new file mode 100644 index 0000000000..0258dc15e4 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.func-sort-c.html @@ -0,0 +1,132 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/estimation_manager - support.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:8510581.0 %
Date:2023-11-29 14:09:54Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers18estimation_manager7Support11getPoseDiffERKN13geometry_msgs5Pose_ISaIvEEES7_0
_ZN16mrs_uav_managers18estimation_manager7Support22frameIdToEstimatorNameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN16mrs_uav_managers18estimation_manager7Support11toLowercaseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE28
_ZN16mrs_uav_managers18estimation_manager7Support16isStringInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS7_SaIS7_EE28
_ZN16mrs_uav_managers18estimation_manager7Support11toSnakeCaseERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE95
_ZN16mrs_uav_managers18estimation_manager7Support13applyPoseDiffERKN13geometry_msgs5Pose_ISaIvEEES7_8944
_ZN16mrs_uav_managers18estimation_manager7Support14uavStateToOdomERKN8mrs_msgs9UavState_ISaIvEEE8946
_ZN16mrs_uav_managers18estimation_manager7Support6noNansERKN13geometry_msgs11Quaternion_ISaIvEEE9841
_ZN16mrs_uav_managers18estimation_manager7Support10msgFromTf2ERKN3tf29TransformE11028
_ZN16mrs_uav_managers18estimation_manager7Support14rotateVecByHdgERKN13geometry_msgs8Vector3_ISaIvEEEd11111
_ZN16mrs_uav_managers18estimation_manager7Support12rotateVectorERKN13geometry_msgs8Vector3_ISaIvEEERKNS2_11Quaternion_IS4_EE22788
_ZN16mrs_uav_managers18estimation_manager7Support11poseFromTf2ERKN3tf29TransformE41917
_ZN16mrs_uav_managers18estimation_manager7Support14pointToVector3ERKN13geometry_msgs6Point_ISaIvEEE42028
_ZN16mrs_uav_managers18estimation_manager7Support11tf2FromPoseERKN13geometry_msgs5Pose_ISaIvEEE53046
_ZN16mrs_uav_managers18estimation_manager7Support6noNansERKN13geometry_msgs17TransformStamped_ISaIvEEE84376
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.func.html b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.func.html new file mode 100644 index 0000000000..239e263e8a --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.func.html @@ -0,0 +1,132 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/estimation_manager - support.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:8510581.0 %
Date:2023-11-29 14:09:54Functions:131586.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers18estimation_manager7Support10msgFromTf2ERKN3tf29TransformE11028
_ZN16mrs_uav_managers18estimation_manager7Support11getPoseDiffERKN13geometry_msgs5Pose_ISaIvEEES7_0
_ZN16mrs_uav_managers18estimation_manager7Support11poseFromTf2ERKN3tf29TransformE41917
_ZN16mrs_uav_managers18estimation_manager7Support11tf2FromPoseERKN13geometry_msgs5Pose_ISaIvEEE53046
_ZN16mrs_uav_managers18estimation_manager7Support11toLowercaseENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE28
_ZN16mrs_uav_managers18estimation_manager7Support11toSnakeCaseERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE95
_ZN16mrs_uav_managers18estimation_manager7Support12rotateVectorERKN13geometry_msgs8Vector3_ISaIvEEERKNS2_11Quaternion_IS4_EE22788
_ZN16mrs_uav_managers18estimation_manager7Support13applyPoseDiffERKN13geometry_msgs5Pose_ISaIvEEES7_8944
_ZN16mrs_uav_managers18estimation_manager7Support14pointToVector3ERKN13geometry_msgs6Point_ISaIvEEE42028
_ZN16mrs_uav_managers18estimation_manager7Support14rotateVecByHdgERKN13geometry_msgs8Vector3_ISaIvEEEd11111
_ZN16mrs_uav_managers18estimation_manager7Support14uavStateToOdomERKN8mrs_msgs9UavState_ISaIvEEE8946
_ZN16mrs_uav_managers18estimation_manager7Support16isStringInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS7_SaIS7_EE28
_ZN16mrs_uav_managers18estimation_manager7Support22frameIdToEstimatorNameERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN16mrs_uav_managers18estimation_manager7Support6noNansERKN13geometry_msgs11Quaternion_ISaIvEEE9841
_ZN16mrs_uav_managers18estimation_manager7Support6noNansERKN13geometry_msgs17TransformStamped_ISaIvEEE84376
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.gcov.html b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.gcov.html new file mode 100644 index 0000000000..2bd29c1e27 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h.gcov.html @@ -0,0 +1,397 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/estimation_manager/support.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers/estimation_manager - support.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:8510581.0 %
Date:2023-11-29 14:09:54Functions:131586.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #pragma once
+       2             : #ifndef ESTIMATION_MANAGER_SUPPORT_H
+       3             : #define ESTIMATION_MANAGER_SUPPORT_H
+       4             : 
+       5             : /* includes //{ */
+       6             : 
+       7             : #include <string.h>
+       8             : 
+       9             : #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
+      10             : 
+      11             : #include <geometry_msgs/TransformStamped.h>
+      12             : #include <geometry_msgs/Pose.h>
+      13             : #include <geometry_msgs/PointStamped.h>
+      14             : 
+      15             : #include <nav_msgs/Odometry.h>
+      16             : 
+      17             : #include <mrs_msgs/UavState.h>
+      18             : 
+      19             : #include <mrs_lib/attitude_converter.h>
+      20             : #include <mrs_lib/transformer.h>
+      21             : 
+      22             : //}
+      23             : 
+      24             : namespace mrs_uav_managers
+      25             : {
+      26             : 
+      27             : namespace estimation_manager
+      28             : {
+      29             : 
+      30             : /*//{ class Support */
+      31             : class Support {
+      32             : 
+      33             : public:
+      34             : 
+      35             :   const static inline std::string waiting_for_string = "\033[0;36mWAITING FOR:\033[0m";
+      36             : 
+      37             :   /*//{ toSnakeCase() */
+      38          95 :   static std::string toSnakeCase(const std::string& str_in) {
+      39             : 
+      40          95 :     std::string str(1, tolower(str_in[0]));
+      41             : 
+      42        1443 :     for (auto it = str_in.begin() + 1; it != str_in.end(); ++it) {
+      43        1348 :       if (isupper(*it) && *(it - 1) != '_' && islower(*(it - 1))) {
+      44          73 :         str += "_";
+      45             :       }
+      46        1348 :       str += *it;
+      47             :     }
+      48             : 
+      49          95 :     std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+      50             : 
+      51          95 :     return str;
+      52             :   }
+      53             :   /*//}*/
+      54             : 
+      55             : /* toLowercase() //{ */
+      56             : 
+      57          28 : static std::string toLowercase(const std::string str_in) {
+      58          28 :   std::string str_out = str_in;
+      59          28 :   std::transform(str_out.begin(), str_out.end(), str_out.begin(), ::tolower);
+      60          28 :   return str_out;
+      61             : }
+      62             : 
+      63             : //}
+      64             : 
+      65             : /* toUppercase() //{ */
+      66             : 
+      67             : static std::string toUppercase(const std::string str_in) {
+      68             :   std::string str_out = str_in;
+      69             :   std::transform(str_out.begin(), str_out.end(), str_out.begin(), ::toupper);
+      70             :   return str_out;
+      71             : }
+      72             : 
+      73             : //}
+      74             : 
+      75             :   /*//{ stateCovToString() */
+      76             :   template <typename StateCov>
+      77             :   static std::string stateCovToString(const StateCov& sc) {
+      78             :     std::stringstream ss;
+      79             :     ss << "State:\n";
+      80             :     for (int i = 0; i < sc.x.rows(); i++) {
+      81             :       for (int j = 0; j < sc.x.cols(); j++) {
+      82             :         ss << sc.x(i, j) << " ";
+      83             :       }
+      84             :       ss << "\n";
+      85             :     }
+      86             :     ss << "Cov:\n";
+      87             :     for (int i = 0; i < sc.P.rows(); i++) {
+      88             :       for (int j = 0; j < sc.P.cols(); j++) {
+      89             :         ss << sc.P(i, j) << " ";
+      90             :       }
+      91             :       ss << "\n";
+      92             :     }
+      93             :     return ss.str();
+      94             :   }
+      95             :   /*//}*/
+      96             : 
+      97             :   /* //{ rotateVecByHdg() */
+      98       11111 :   static tf2::Vector3 rotateVecByHdg(const geometry_msgs::Vector3& vec_in, const double hdg_in) {
+      99             : 
+     100       11111 :     const tf2::Quaternion q_hdg = mrs_lib::AttitudeConverter(0, 0, 0).setHeading(hdg_in);
+     101             : 
+     102       11105 :     const tf2::Vector3 vec_tf2(vec_in.x, vec_in.y, vec_in.z);
+     103             : 
+     104       11088 :     const tf2::Vector3 vec_rotated = tf2::quatRotate(q_hdg, vec_tf2);
+     105             : 
+     106       22196 :     return vec_rotated;
+     107             :   }
+     108             :   //}
+     109             : 
+     110             :   /* noNans() //{ */
+     111       84376 :   static bool noNans(const geometry_msgs::TransformStamped& tf) {
+     112             : 
+     113      253072 :     return (std::isfinite(tf.transform.rotation.x) && std::isfinite(tf.transform.rotation.y) && std::isfinite(tf.transform.rotation.z) &&
+     114      337393 :             std::isfinite(tf.transform.rotation.w) && std::isfinite(tf.transform.translation.x) && std::isfinite(tf.transform.translation.y) &&
+     115      168712 :             std::isfinite(tf.transform.translation.z));
+     116             :   }
+     117             :   //}
+     118             : 
+     119             :   /* noNans() //{ */
+     120        9841 :   static bool noNans(const geometry_msgs::Quaternion& q) {
+     121             : 
+     122        9841 :     return (std::isfinite(q.x) && std::isfinite(q.y) && std::isfinite(q.z) && std::isfinite(q.w));
+     123             :   }
+     124             :   //}
+     125             : 
+     126             :   /* isZeroQuaternion() //{ */
+     127             :   static bool isZeroQuaternion(const geometry_msgs::Quaternion& q) {
+     128             : 
+     129             :     return (q.x == 0 && q.y == 0 && q.z == 0 && q.w == 0);
+     130             :   }
+     131             :   //}
+     132             : 
+     133             :   /* tf2FromPose() //{ */
+     134             : 
+     135       53046 :   static tf2::Transform tf2FromPose(const geometry_msgs::Pose& pose_in) {
+     136             : 
+     137       53046 :     tf2::Vector3 position(pose_in.position.x, pose_in.position.y, pose_in.position.z);
+     138             : 
+     139       53040 :     tf2::Quaternion q;
+     140       53025 :     tf2::fromMsg(pose_in.orientation, q);
+     141             : 
+     142       53030 :     tf2::Transform tf_out(q, position);
+     143             : 
+     144      105918 :     return tf_out;
+     145             :   }
+     146             : 
+     147             :   //}
+     148             : 
+     149             :   /* poseFromTf2() //{ */
+     150             : 
+     151       41917 :   static geometry_msgs::Pose poseFromTf2(const tf2::Transform& tf_in) {
+     152             : 
+     153       41917 :     geometry_msgs::Pose pose_out;
+     154       41842 :     pose_out.position.x = tf_in.getOrigin().getX();
+     155       41921 :     pose_out.position.y = tf_in.getOrigin().getY();
+     156       41938 :     pose_out.position.z = tf_in.getOrigin().getZ();
+     157             : 
+     158       41981 :     pose_out.orientation = tf2::toMsg(tf_in.getRotation());
+     159             : 
+     160       41979 :     return pose_out;
+     161             :   }
+     162             : 
+     163             :   //}
+     164             : 
+     165             :   /* msgFromTf2() //{ */
+     166       11028 :   static geometry_msgs::Transform msgFromTf2(const tf2::Transform& tf_in) {
+     167             : 
+     168       11028 :     geometry_msgs::Transform tf_out;
+     169       11028 :     tf_out.translation.x = tf_in.getOrigin().getX();
+     170       11028 :     tf_out.translation.y = tf_in.getOrigin().getY();
+     171       11028 :     tf_out.translation.z = tf_in.getOrigin().getZ();
+     172       11028 :     tf_out.rotation = tf2::toMsg(tf_in.getRotation());
+     173             : 
+     174       11028 :     return tf_out;
+     175             :   }
+     176             : 
+     177             :   //}
+     178             :   
+     179             :   /* tf2FromMsg() //{ */
+     180             :   static tf2::Transform tf2FromMsg(const geometry_msgs::Transform& tf_in) {
+     181             : 
+     182             :     tf2::Transform tf_out;
+     183             :     tf_out.setOrigin(tf2::Vector3(tf_in.translation.x, tf_in.translation.y, tf_in.translation.z));
+     184             :     tf_out.setRotation(tf2::Quaternion(tf_in.rotation.x, tf_in.rotation.y, tf_in.rotation.z, tf_in.rotation.w));
+     185             : 
+     186             :     return tf_out;
+     187             :   }
+     188             : 
+     189             :   //}
+     190             :  
+     191             :   /* pointToVector3() //{ */
+     192             : 
+     193       42028 :   static geometry_msgs::Vector3 pointToVector3(const geometry_msgs::Point& point_in) {
+     194             : 
+     195       42028 :     geometry_msgs::Vector3 vec_out;
+     196       42028 :     vec_out.x = point_in.x;
+     197       42028 :     vec_out.y = point_in.y;
+     198       42028 :     vec_out.z = point_in.z;
+     199             : 
+     200       42028 :     return vec_out;
+     201             :   }
+     202             : 
+     203             :   //}
+     204             : 
+     205             :   /*//{ rotateVector() */
+     206       22788 :   static geometry_msgs::Vector3 rotateVector(const geometry_msgs::Vector3& vec_in, const geometry_msgs::Quaternion& q_in) {
+     207             : 
+     208             :     try {
+     209       22788 :       Eigen::Matrix3d        R = mrs_lib::AttitudeConverter(q_in);
+     210       22788 :       Eigen::Vector3d        vec_in_eigen(vec_in.x, vec_in.y, vec_in.z);
+     211       22783 :       Eigen::Vector3d        vec_eigen_rotated = R * vec_in_eigen;
+     212       22778 :       geometry_msgs::Vector3 vec_out;
+     213       22728 :       vec_out.x = vec_eigen_rotated[0];
+     214       22688 :       vec_out.y = vec_eigen_rotated[1];
+     215       22715 :       vec_out.z = vec_eigen_rotated[2];
+     216       22730 :       return vec_out;
+     217             :     }
+     218           0 :     catch (...) {
+     219           0 :       ROS_ERROR_THROTTLE(1.0, "[Support::rotateVector()]: failed");
+     220           0 :       return vec_in;
+     221             :     }
+     222             :   }
+     223             :   /*//}*/
+     224             : 
+     225             :   /*//{ uavStateToOdom() */
+     226        8946 :   static nav_msgs::Odometry uavStateToOdom(const mrs_msgs::UavState& uav_state) {
+     227        8946 :     nav_msgs::Odometry odom;
+     228        8946 :     odom.header              = uav_state.header;
+     229        8946 :     odom.child_frame_id      = uav_state.child_frame_id;
+     230        8946 :     odom.pose.pose           = uav_state.pose;
+     231        8946 :     odom.twist.twist.angular = uav_state.velocity.angular;
+     232             : 
+     233        8946 :     tf2::Quaternion q;
+     234        8946 :     tf2::fromMsg(odom.pose.pose.orientation, q);
+     235        8946 :     odom.twist.twist.linear = Support::rotateVector(uav_state.velocity.linear, mrs_lib::AttitudeConverter(q.inverse()));
+     236             : 
+     237       17892 :     return odom;
+     238             :   }
+     239             :   /*//}*/
+     240             : 
+     241             :   /*//{ getPoseDiff() */
+     242           0 :   static geometry_msgs::Pose getPoseDiff(const geometry_msgs::Pose& p1, const geometry_msgs::Pose& p2) {
+     243             : 
+     244           0 :     tf2::Vector3 v1, v2;
+     245           0 :     tf2::fromMsg(p1.position, v1);
+     246           0 :     tf2::fromMsg(p2.position, v2);
+     247           0 :     const tf2::Vector3 v3 = v1 - v2;
+     248             : 
+     249           0 :     tf2::Quaternion q1, q2;
+     250           0 :     tf2::fromMsg(p1.orientation, q1);
+     251           0 :     tf2::fromMsg(p2.orientation, q2);
+     252           0 :     tf2::Quaternion q3 = q2 * q1.inverse();
+     253           0 :     q3.normalize();
+     254             : 
+     255           0 :     geometry_msgs::Pose pose_diff;
+     256           0 :     tf2::toMsg(v3, pose_diff.position);
+     257           0 :     pose_diff.orientation = tf2::toMsg(q3);
+     258             : 
+     259           0 :     return pose_diff;
+     260             :   }
+     261             :   /*//}*/
+     262             : 
+     263             :   /*//{ applyPoseDiff() */
+     264        8944 :   static geometry_msgs::Pose applyPoseDiff(const geometry_msgs::Pose& pose_in, const geometry_msgs::Pose& pose_diff) {
+     265             : 
+     266        8944 :     tf2::Vector3    pos_in;
+     267        8944 :     tf2::Quaternion q_in;
+     268        8944 :     tf2::fromMsg(pose_in.position, pos_in);
+     269        8944 :     tf2::fromMsg(pose_in.orientation, q_in);
+     270             : 
+     271        8944 :     tf2::Vector3    pos_diff;
+     272        8944 :     tf2::Quaternion q_diff;
+     273        8944 :     tf2::fromMsg(pose_diff.position, pos_diff);
+     274        8944 :     tf2::fromMsg(pose_diff.orientation, q_diff);
+     275             : 
+     276        8944 :     const tf2::Vector3    pos_out = tf2::quatRotate(q_diff.inverse(), (pos_in - pos_diff));
+     277        8944 :     const tf2::Quaternion q_out   = q_diff.inverse() * q_in;
+     278             : 
+     279        8944 :     geometry_msgs::Pose pose_out;
+     280        8944 :     tf2::toMsg(pos_out, pose_out.position);
+     281        8944 :     pose_out.orientation = tf2::toMsg(q_out);
+     282             : 
+     283       17888 :     return pose_out;
+     284             :   }
+     285             : 
+     286             :   //}
+     287             : 
+     288             :   /*//{ loadParamFile() */
+     289             :   static void loadParamFile(const std::string& file_path, const std::string& ns = "") {
+     290             :     std::string command = "rosparam load " + file_path + " " + ns;
+     291             :     int         result  = std::system(command.c_str());
+     292             :     if (result != 0) {
+     293             :       ROS_ERROR_STREAM("Could not set config file " << file_path << " to the parameter server.");
+     294             :     }
+     295             :   }
+     296             :   /*//}*/
+     297             : 
+     298             :   /*//{ isStringInVector() */
+     299          28 :   static bool isStringInVector(const std::string& value, const std::vector<std::string>& str_vec) {
+     300          28 :     return std::find(str_vec.begin(), str_vec.end(), value) != str_vec.end();
+     301             :   }
+     302             :   /*//}*/
+     303             : 
+     304             :   /*//{ frameIdToEstimatorName() */
+     305           0 :   static std::string frameIdToEstimatorName(const std::string& str_in) {
+     306           0 :     const std::string str_tmp = str_in.substr(str_in.find("/")+1, str_in.size());
+     307           0 :     return str_tmp.substr(0, str_tmp.find("_origin") );
+     308             :   }
+     309             :   /*//}*/
+     310             : 
+     311             : private:
+     312             :   Support() {
+     313             :   }
+     314             : };
+     315             : /*//}*/
+     316             : 
+     317             : }  // namespace estimation_manager
+     318             : 
+     319             : }  // namespace mrs_uav_managers
+     320             : 
+     321             : #endif  // ESTIMATION_MANAGER_SUPPORT_H
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/index-sort-f.html b/mrs_uav_managers/include/mrs_uav_managers/index-sort-f.html new file mode 100644 index 0000000000..2daaa597f5 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managersHitTotalCoverage
Test:coverage.infoLines:11100.0 %
Date:2023-11-29 14:09:54Functions:1250.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
tracker.h +
100.0%
+
100.0 %1 / 150.0 %1 / 2
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/index-sort-l.html b/mrs_uav_managers/include/mrs_uav_managers/index-sort-l.html new file mode 100644 index 0000000000..0782c67b40 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managersHitTotalCoverage
Test:coverage.infoLines:11100.0 %
Date:2023-11-29 14:09:54Functions:1250.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
tracker.h +
100.0%
+
100.0 %1 / 150.0 %1 / 2
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/index.html b/mrs_uav_managers/include/mrs_uav_managers/index.html new file mode 100644 index 0000000000..510f9785e9 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managersHitTotalCoverage
Test:coverage.infoLines:11100.0 %
Date:2023-11-29 14:09:54Functions:1250.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
tracker.h +
100.0%
+
100.0 %1 / 150.0 %1 / 2
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/tracker.h.func-sort-c.html b/mrs_uav_managers/include/mrs_uav_managers/tracker.h.func-sort-c.html new file mode 100644 index 0000000000..e91d5c3d09 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/tracker.h.func-sort-c.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/tracker.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers - tracker.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:11100.0 %
Date:2023-11-29 14:09:54Functions:1250.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers7TrackerD0Ev0
_ZN16mrs_uav_managers7TrackerD2Ev7
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/tracker.h.func.html b/mrs_uav_managers/include/mrs_uav_managers/tracker.h.func.html new file mode 100644 index 0000000000..88f9f6fa8a --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/tracker.h.func.html @@ -0,0 +1,80 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/tracker.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers - tracker.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:11100.0 %
Date:2023-11-29 14:09:54Functions:1250.0 %
+
+ +
+ + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers7TrackerD0Ev0
_ZN16mrs_uav_managers7TrackerD2Ev7
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/mrs_uav_managers/tracker.h.gcov.html b/mrs_uav_managers/include/mrs_uav_managers/tracker.h.gcov.html new file mode 100644 index 0000000000..937e8f5b10 --- /dev/null +++ b/mrs_uav_managers/include/mrs_uav_managers/tracker.h.gcov.html @@ -0,0 +1,288 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/mrs_uav_managers/tracker.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/mrs_uav_managers - tracker.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:11100.0 %
Date:2023-11-29 14:09:54Functions:1250.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #ifndef MRS_UAV_TRACKER_H
+       2             : #define MRS_UAV_TRACKER_H
+       3             : 
+       4             : /* includes //{ */
+       5             : 
+       6             : #include <ros/ros.h>
+       7             : 
+       8             : #include <mrs_uav_managers/control_manager/common_handlers.h>
+       9             : #include <mrs_uav_managers/control_manager/private_handlers.h>
+      10             : 
+      11             : #include <mrs_msgs/TrackerCommand.h>
+      12             : #include <mrs_msgs/TrackerStatus.h>
+      13             : #include <mrs_msgs/UavState.h>
+      14             : 
+      15             : #include <mrs_msgs/Float64Srv.h>
+      16             : #include <mrs_msgs/Float64SrvRequest.h>
+      17             : #include <mrs_msgs/Float64SrvResponse.h>
+      18             : 
+      19             : #include <mrs_msgs/Float64.h>
+      20             : 
+      21             : #include <mrs_msgs/ReferenceSrv.h>
+      22             : #include <mrs_msgs/ReferenceSrvRequest.h>
+      23             : #include <mrs_msgs/ReferenceSrvResponse.h>
+      24             : 
+      25             : #include <mrs_msgs/VelocityReferenceSrv.h>
+      26             : #include <mrs_msgs/VelocityReferenceSrvRequest.h>
+      27             : #include <mrs_msgs/VelocityReferenceSrvResponse.h>
+      28             : 
+      29             : #include <mrs_msgs/TrajectoryReferenceSrv.h>
+      30             : #include <mrs_msgs/TrajectoryReferenceSrvRequest.h>
+      31             : #include <mrs_msgs/TrajectoryReferenceSrvResponse.h>
+      32             : 
+      33             : #include <std_srvs/Trigger.h>
+      34             : #include <std_srvs/TriggerRequest.h>
+      35             : #include <std_srvs/TriggerResponse.h>
+      36             : 
+      37             : #include <std_srvs/SetBool.h>
+      38             : #include <std_srvs/SetBoolRequest.h>
+      39             : #include <std_srvs/SetBoolResponse.h>
+      40             : 
+      41             : #include <mrs_msgs/DynamicsConstraintsSrv.h>
+      42             : #include <mrs_msgs/DynamicsConstraintsSrvRequest.h>
+      43             : #include <mrs_msgs/DynamicsConstraintsSrvResponse.h>
+      44             : 
+      45             : #include <mrs_uav_managers/controller.h>
+      46             : 
+      47             : //}
+      48             : 
+      49             : namespace mrs_uav_managers
+      50             : {
+      51             : 
+      52             : class Tracker {
+      53             : 
+      54             : public:
+      55             :   /**
+      56             :    * @brief It is called once for every tracker. The runtime is not limited.
+      57             :    *
+      58             :    * @param nh the node handle of the ControlManager
+      59             :    * @param uav_name the UAV name (e.g., "uav1")
+      60             :    * @param common_handlers handlers shared between trackers and controllers
+      61             :    * @param private_handlers handlers provided individually to each tracker
+      62             :    *
+      63             :    * @return true if success
+      64             :    */
+      65             :   virtual bool initialize(const ros::NodeHandle &nh, std::shared_ptr<mrs_uav_managers::control_manager::CommonHandlers_t> common_handlers,
+      66             :                           std::shared_ptr<mrs_uav_managers::control_manager::PrivateHandlers_t> private_handlers) = 0;
+      67             : 
+      68             :   /**
+      69             :    * @brief It is called before the trackers output will be required and used. Should not take much time (within miliseconds).
+      70             :    *
+      71             :    * @param last_tracker_cmd the last command produced by the last active tracker. Should be used as an initial condition to maintain a smooth reference.
+      72             :    *
+      73             :    * @return true if success and message
+      74             :    */
+      75             :   virtual std::tuple<bool, std::string> activate(const std::optional<mrs_msgs::TrackerCommand> &last_tracker_cmd) = 0;
+      76             : 
+      77             :   /**
+      78             :    * @brief is called when this trackers output is no longer needed. However, it can be activated later.
+      79             :    */
+      80             :   virtual void deactivate(void) = 0;
+      81             : 
+      82             :   /**
+      83             :    * @brief It is called during every switch of reference frames of the UAV state estimate.
+      84             :    * The tracker should recalculate its internal states from old the frame to the new one.
+      85             :    *
+      86             :    * @param new_uav_state the new UavState which will come in the next update()
+      87             :    *
+      88             :    * @return a service response
+      89             :    */
+      90             :   virtual const std_srvs::TriggerResponse::ConstPtr switchOdometrySource(const mrs_msgs::UavState &new_uav_state) = 0;
+      91             : 
+      92             :   /**
+      93             :    * @brief Request for reseting the tracker's states given the UAV is static.
+      94             :    *
+      95             :    * @return true if success
+      96             :    */
+      97             :   virtual bool resetStatic(void) = 0;
+      98             : 
+      99             :   /**
+     100             :    * @brief The most important routine. It is called with every state estimator update and it should produce a new reference for the controllers.
+     101             :    *        The run time should be as short as possible (<= 1 ms).
+     102             :    *
+     103             :    * @param uav_state the latest UAV state estimate
+     104             :    * @param last_attitude_cmd the last controller's output command (may be useful)
+     105             :    *
+     106             :    * @return the new reference for the controllers
+     107             :    */
+     108             :   virtual std::optional<mrs_msgs::TrackerCommand> update(const mrs_msgs::UavState &uav_state, const Controller::ControlOutput &last_control_output) = 0;
+     109             : 
+     110             :   /**
+     111             :    * @brief A request for the tracker's status.
+     112             :    *
+     113             :    * @return the tracker's status
+     114             :    */
+     115             :   virtual const mrs_msgs::TrackerStatus getStatus() = 0;
+     116             : 
+     117             :   /**
+     118             :    * @brief Request for a flight to a given coordinates.
+     119             :    *
+     120             :    * @param cmd the reference
+     121             :    *
+     122             :    * @return a service response
+     123             :    */
+     124             :   virtual const mrs_msgs::ReferenceSrvResponse::ConstPtr setReference(const mrs_msgs::ReferenceSrvRequest::ConstPtr &cmd) = 0;
+     125             : 
+     126             :   /**
+     127             :    * @brief Request for desired velocity reference
+     128             :    *
+     129             :    * @param cmd the reference
+     130             :    *
+     131             :    * @return a service response
+     132             :    */
+     133             :   virtual const mrs_msgs::VelocityReferenceSrvResponse::ConstPtr setVelocityReference(const mrs_msgs::VelocityReferenceSrvRequest::ConstPtr &cmd) = 0;
+     134             : 
+     135             :   /**
+     136             :    * @brief Request for a flight along a given trajectory
+     137             :    *
+     138             :    * @param cmd the reference trajectory
+     139             :    *
+     140             :    * @return a service response
+     141             :    */
+     142             :   virtual const mrs_msgs::TrajectoryReferenceSrvResponse::ConstPtr setTrajectoryReference(const mrs_msgs::TrajectoryReferenceSrvRequest::ConstPtr &cmd) = 0;
+     143             : 
+     144             :   /**
+     145             :    * @brief Request for stopping the motion of the UAV.
+     146             :    *
+     147             :    * @param trigger service request
+     148             :    *
+     149             :    * @return a service response
+     150             :    */
+     151             :   virtual const std_srvs::TriggerResponse::ConstPtr hover(const std_srvs::TriggerRequest::ConstPtr &cmd) = 0;
+     152             : 
+     153             :   /**
+     154             :    * @brief Request to goto to the first trajectory coordinate.
+     155             :    *
+     156             :    * @param trigger service request
+     157             :    *
+     158             :    * @return a service response
+     159             :    */
+     160             :   virtual const std_srvs::TriggerResponse::ConstPtr gotoTrajectoryStart(const std_srvs::TriggerRequest::ConstPtr &cmd) = 0;
+     161             : 
+     162             :   /**
+     163             :    * @brief Request to start tracking of the pre-loaded trajectory
+     164             :    *
+     165             :    * @param trigger service request
+     166             :    *
+     167             :    * @return a service response
+     168             :    */
+     169             :   virtual const std_srvs::TriggerResponse::ConstPtr startTrajectoryTracking(const std_srvs::TriggerRequest::ConstPtr &cmd) = 0;
+     170             : 
+     171             :   /**
+     172             :    * @brief Request to stop tracking of the pre-loaded trajectory. The hover() routine will be engaged, thus it should be implemented by the tracker.
+     173             :    *
+     174             :    * @param trigger service request
+     175             :    *
+     176             :    * @return a service response
+     177             :    */
+     178             :   virtual const std_srvs::TriggerResponse::ConstPtr stopTrajectoryTracking(const std_srvs::TriggerRequest::ConstPtr &cmd) = 0;
+     179             : 
+     180             :   /**
+     181             :    * @brief Request to resume the previously stopped trajectory tracking.
+     182             :    *
+     183             :    * @param trigger service request
+     184             :    *
+     185             :    * @return a service response
+     186             :    */
+     187             :   virtual const std_srvs::TriggerResponse::ConstPtr resumeTrajectoryTracking(const std_srvs::TriggerRequest::ConstPtr &cmd) = 0;
+     188             : 
+     189             :   /**
+     190             :    * @brief Request for enabling/disabling callbacks.
+     191             :    *
+     192             :    * @param cmd service request
+     193             :    *
+     194             :    * @return a service response
+     195             :    */
+     196             :   virtual const std_srvs::SetBoolResponse::ConstPtr enableCallbacks(const std_srvs::SetBoolRequest::ConstPtr &cmd) = 0;
+     197             : 
+     198             :   /**
+     199             :    * @brief Request for setting new constraints.
+     200             :    *
+     201             :    * @param constraints to be set
+     202             :    *
+     203             :    * @return a service response
+     204             :    */
+     205             :   virtual const mrs_msgs::DynamicsConstraintsSrvResponse::ConstPtr setConstraints(const mrs_msgs::DynamicsConstraintsSrvRequest::ConstPtr &constraints) = 0;
+     206             : 
+     207           7 :   virtual ~Tracker() = default;
+     208             : };
+     209             : 
+     210             : }  // namespace mrs_uav_managers
+     211             : 
+     212             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/index-sort-f.html b/mrs_uav_managers/include/transform_manager/index-sort-f.html new file mode 100644 index 0000000000..23751c819f --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_managerHitTotalCoverage
Test:coverage.infoLines:18639547.1 %
Date:2023-11-29 14:09:54Functions:111957.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
tf_mapping_origin.h +
0.0%
+
0.0 %0 / 1580.0 %0 / 5
tf_source.h +
78.5%78.5%
+
78.5 %186 / 23778.6 %11 / 14
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/index-sort-l.html b/mrs_uav_managers/include/transform_manager/index-sort-l.html new file mode 100644 index 0000000000..8a3801d18f --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_managerHitTotalCoverage
Test:coverage.infoLines:18639547.1 %
Date:2023-11-29 14:09:54Functions:111957.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
tf_mapping_origin.h +
0.0%
+
0.0 %0 / 1580.0 %0 / 5
tf_source.h +
78.5%78.5%
+
78.5 %186 / 23778.6 %11 / 14
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/index.html b/mrs_uav_managers/include/transform_manager/index.html new file mode 100644 index 0000000000..95c1375d4c --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_managerHitTotalCoverage
Test:coverage.infoLines:18639547.1 %
Date:2023-11-29 14:09:54Functions:111957.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
tf_mapping_origin.h +
0.0%
+
0.0 %0 / 1580.0 %0 / 5
tf_source.h +
78.5%78.5%
+
78.5 %186 / 23778.6 %11 / 14
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.func-sort-c.html b/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.func-sort-c.html new file mode 100644 index 0000000000..e161070f13 --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.func-sort-c.html @@ -0,0 +1,92 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager/tf_mapping_origin.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_manager - tf_mapping_origin.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:01580.0 %
Date:2023-11-29 14:09:54Functions:050.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15TfMappingOrigin12getPrintNameB5cxx11Ev0
_ZN16mrs_uav_managers15TfMappingOrigin22callbackMappingOdomAltEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZN16mrs_uav_managers15TfMappingOrigin22callbackMappingOdomLatEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZN16mrs_uav_managers15TfMappingOrigin22callbackMappingOdomRotEN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE0
_ZN16mrs_uav_managers15TfMappingOriginC2EN3ros10NodeHandleESt10shared_ptrIN7mrs_lib11ParamLoaderEERKS3_INS4_20TransformBroadcasterEES3_INS_18estimation_manager16CommonHandlers_tEE0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.func.html b/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.func.html new file mode 100644 index 0000000000..d1c8726860 --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.func.html @@ -0,0 +1,92 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager/tf_mapping_origin.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_manager - tf_mapping_origin.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:01580.0 %
Date:2023-11-29 14:09:54Functions:050.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15TfMappingOrigin12getPrintNameB5cxx11Ev0
_ZN16mrs_uav_managers15TfMappingOrigin22callbackMappingOdomAltEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZN16mrs_uav_managers15TfMappingOrigin22callbackMappingOdomLatEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZN16mrs_uav_managers15TfMappingOrigin22callbackMappingOdomRotEN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE0
_ZN16mrs_uav_managers15TfMappingOriginC2EN3ros10NodeHandleESt10shared_ptrIN7mrs_lib11ParamLoaderEERKS3_INS4_20TransformBroadcasterEES3_INS_18estimation_manager16CommonHandlers_tEE0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.gcov.html b/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.gcov.html new file mode 100644 index 0000000000..47f682947e --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/tf_mapping_origin.h.gcov.html @@ -0,0 +1,466 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager/tf_mapping_origin.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_manager - tf_mapping_origin.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:01580.0 %
Date:2023-11-29 14:09:54Functions:050.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #pragma once
+       2             : #ifndef TF_MAPPING_ORIGIN_H
+       3             : #define TF_MAPPING_ORIGIN_H
+       4             : 
+       5             : #include <ros/ros.h>
+       6             : 
+       7             : #include <mrs_lib/param_loader.h>
+       8             : #include <mrs_lib/subscribe_handler.h>
+       9             : #include <mrs_lib/transform_broadcaster.h>
+      10             : #include <mrs_lib/attitude_converter.h>
+      11             : #include <mrs_lib/publisher_handler.h>
+      12             : 
+      13             : #include <nav_msgs/Odometry.h>
+      14             : #include <geometry_msgs/QuaternionStamped.h>
+      15             : #include <geometry_msgs/TransformStamped.h>
+      16             : 
+      17             : #include <mrs_uav_managers/estimation_manager/support.h>
+      18             : #include <mrs_uav_managers/estimation_manager/common_handlers.h>
+      19             : 
+      20             : namespace mrs_uav_managers
+      21             : {
+      22             : 
+      23             : /*//{ class TfMappingOrigin */
+      24             : class TfMappingOrigin {
+      25             : 
+      26             :   using Support = estimation_manager::Support;
+      27             : 
+      28             : public:
+      29             :   /*//{ constructor */
+      30           0 :   TfMappingOrigin(ros::NodeHandle nh, std::shared_ptr<mrs_lib::ParamLoader> param_loader, const std::shared_ptr<mrs_lib::TransformBroadcaster>& broadcaster,
+      31             :                   const std::shared_ptr<estimation_manager::CommonHandlers_t> ch)
+      32           0 :       : nh_(nh), broadcaster_(broadcaster), ch_(ch) {
+      33             : 
+      34           0 :     ROS_INFO("[%s]: initializing", getPrintName().c_str());
+      35             : 
+      36           0 :     const std::string yaml_prefix = "mrs_uav_managers/transform_manager/mapping_origin_tf/";
+      37             : 
+      38             :     /*//{ load mapping origin parameters */
+      39           0 :     param_loader->loadParam(yaml_prefix + "debug_prints", debug_prints_);
+      40           0 :     param_loader->loadParam(yaml_prefix + "lateral_topic", lateral_topic_);
+      41           0 :     param_loader->loadParam(yaml_prefix + "altitude_topic", altitude_topic_);
+      42           0 :     param_loader->loadParam(yaml_prefix + "orientation_topic", orientation_topic_);
+      43           0 :     param_loader->loadParam(yaml_prefix + "inverted", tf_inverted_);
+      44           0 :     param_loader->loadParam(yaml_prefix + "custom_frame_id/enabled", custom_frame_id_enabled_);
+      45             : 
+      46           0 :     if (custom_frame_id_enabled_) {
+      47           0 :       param_loader->loadParam(yaml_prefix + "custom_frame_id/frame_id", custom_frame_id_);
+      48             :     }
+      49             : 
+      50           0 :     if (!param_loader->loadedSuccessfully()) {
+      51           0 :       ROS_ERROR("[%s]: Could not load all non-optional parameters. Shutting down.", getPrintName().c_str());
+      52           0 :       ros::shutdown();
+      53             :     }
+      54             : 
+      55             :     /*//}*/
+      56             : 
+      57             :     /*//{ initialize subscribers */
+      58           0 :     mrs_lib::SubscribeHandlerOptions shopts;
+      59           0 :     shopts.nh                 = nh_;
+      60           0 :     shopts.node_name          = getPrintName();
+      61           0 :     shopts.no_message_timeout = mrs_lib::no_timeout;
+      62           0 :     shopts.threadsafe         = true;
+      63           0 :     shopts.autostart          = true;
+      64           0 :     shopts.queue_size         = 10;
+      65           0 :     shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+      66             : 
+      67             :     sh_mapping_odom_lat_ =
+      68           0 :         mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, "/" + ch_->uav_name + "/" + lateral_topic_, &TfMappingOrigin::callbackMappingOdomLat, this);
+      69             : 
+      70           0 :     if (orientation_topic_ != lateral_topic_) {
+      71           0 :       sh_mapping_odom_rot_ = mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped>(shopts, "/" + ch_->uav_name + "/" + orientation_topic_.c_str(),
+      72           0 :                                                                                          &TfMappingOrigin::callbackMappingOdomRot, this);
+      73             :     }
+      74             : 
+      75           0 :     if (altitude_topic_ != lateral_topic_) {
+      76           0 :       sh_mapping_odom_alt_ = mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, "/" + ch_->uav_name + "/" + altitude_topic_.c_str(),
+      77           0 :                                                                            &TfMappingOrigin::callbackMappingOdomAlt, this);
+      78             :     }
+      79             :     /*//}*/
+      80             : 
+      81           0 :     ph_map_delay_ = mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>(nh_, "map_delay_out", 10);
+      82             : 
+      83           0 :     is_initialized_ = true;
+      84           0 :     ROS_INFO("[%s]: initialized", getPrintName().c_str());
+      85           0 :   }
+      86             :   /*//}*/
+      87             : 
+      88             :   /*//{ getName() */
+      89             :   std::string getName() {
+      90             :     return name_;
+      91             :   }
+      92             :   /*//}*/
+      93             : 
+      94             :   /*//{ getPrintName() */
+      95           0 :   std::string getPrintName() {
+      96           0 :     return ch_->nodelet_name + "/" + name_;
+      97             :   }
+      98             :   /*//}*/
+      99             : 
+     100             : private:
+     101             :   const std::string name_ = "TfMappingOrigin";
+     102             : 
+     103             :   ros::NodeHandle nh_;
+     104             : 
+     105             :   std::shared_ptr<mrs_lib::TransformBroadcaster> broadcaster_;
+     106             : 
+     107             :   std::shared_ptr<estimation_manager::CommonHandlers_t> ch_;
+     108             : 
+     109             :   std::atomic_bool is_initialized_ = false;
+     110             : 
+     111             :   mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped> ph_map_delay_;
+     112             : 
+     113             :   bool        debug_prints_;
+     114             :   bool        tf_inverted_;
+     115             :   bool        custom_frame_id_enabled_;
+     116             :   std::string custom_frame_id_;
+     117             :   double      cache_duration_;
+     118             : 
+     119             :   std::string                                   lateral_topic_;
+     120             :   mrs_lib::SubscribeHandler<nav_msgs::Odometry> sh_mapping_odom_lat_;
+     121             :   std::vector<nav_msgs::Odometry>               vec_mapping_odom_lat_;
+     122             :   std::atomic_bool                              got_mapping_odom_lat_ = false;
+     123             :   std::atomic<double>                           timestamp_lat_;
+     124             : 
+     125             :   /*//{ callbackMappingOdomLat() */
+     126             : 
+     127           0 :   void callbackMappingOdomLat(const nav_msgs::Odometry::ConstPtr msg) {
+     128             : 
+     129           0 :     if (!is_initialized_) {
+     130           0 :       return;
+     131             :     }
+     132             : 
+     133           0 :     timestamp_lat_ = msg->header.stamp.toSec();
+     134             : 
+     135           0 :     if (!got_mapping_odom_lat_) {
+     136           0 :       got_mapping_odom_lat_ = true;
+     137             :     }
+     138             : 
+     139           0 :     if (!got_mapping_odom_rot_ && orientation_topic_ == lateral_topic_) {
+     140           0 :       got_mapping_odom_rot_ = true;
+     141             :     }
+     142             : 
+     143           0 :     if (!got_mapping_odom_alt_ && altitude_topic_ == lateral_topic_) {
+     144           0 :       got_mapping_odom_alt_ = true;
+     145             :     }
+     146             : 
+     147           0 :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TfMappingOrigin::callbackMappingOdomLat", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     148             : 
+     149           0 :     const double hdg_mapping_old = mrs_lib::AttitudeConverter(msg->pose.pose.orientation).getHeading();
+     150             : 
+     151             :     /* publish mapping origin tf //{ */
+     152             : 
+     153           0 :     bool clear_needed = false;
+     154             : 
+     155           0 :     if (got_mapping_odom_rot_ && got_mapping_odom_alt_) {
+     156           0 :       std::scoped_lock lock(mtx_mapping_odom_rot_);
+     157             : 
+     158             :       // Copy mapping odometry
+     159           0 :       nav_msgs::Odometry mapping_odom;
+     160           0 :       mapping_odom = *msg;
+     161             : 
+     162             :       // Find corresponding orientation
+     163           0 :       geometry_msgs::QuaternionStamped rot_tmp           = *sh_mapping_odom_rot_.getMsg();  // start with newest msg
+     164           0 :       ros::Time                        dbg_timestamp_rot = rot_tmp.header.stamp;
+     165           0 :       tf2::Quaternion                  tf2_rot;
+     166             : 
+     167           0 :       for (size_t i = 0; i < vec_mapping_odom_rot_.size(); i++) {
+     168           0 :         if (mapping_odom.header.stamp < vec_mapping_odom_rot_.at(i).header.stamp) {
+     169             : 
+     170             :           // Choose an orientation with closest timestamp
+     171           0 :           double time_diff      = std::fabs(vec_mapping_odom_rot_.at(i).header.stamp.toSec() - mapping_odom.header.stamp.toSec());
+     172           0 :           double time_diff_prev = std::numeric_limits<double>::max();
+     173           0 :           if (i > 0) {
+     174           0 :             time_diff_prev = std::fabs(vec_mapping_odom_rot_.at(i - 1).header.stamp.toSec() - mapping_odom.header.stamp.toSec());
+     175             :           }
+     176           0 :           if (time_diff_prev < time_diff && i > 0) {
+     177           0 :             i = i - 1;
+     178             :           }
+     179             : 
+     180             :           // Cache is too small if it is full and its oldest element is used
+     181           0 :           if (clear_needed && i == 0) {
+     182           0 :             ROS_WARN_THROTTLE(1.0, "[%s] Mapping orientation cache is too small.", getPrintName().c_str());
+     183             :           }
+     184           0 :           rot_tmp           = vec_mapping_odom_rot_.at(i);
+     185           0 :           dbg_timestamp_rot = vec_mapping_odom_rot_.at(i).header.stamp;
+     186           0 :           break;
+     187             :         }
+     188             :       }
+     189             : 
+     190           0 :       tf2_rot = mrs_lib::AttitudeConverter(rot_tmp.quaternion);
+     191             : 
+     192             :       // Obtain heading from orientation
+     193           0 :       double hdg = 0;
+     194             :       try {
+     195           0 :         hdg = mrs_lib::AttitudeConverter(rot_tmp.quaternion).getHeading();
+     196             :       }
+     197           0 :       catch (...) {
+     198           0 :         ROS_WARN("[%s]: failed to getHeading() from rot_tmp", getPrintName().c_str());
+     199             :       }
+     200             : 
+     201             :       // Build rotation matrix from difference between new heading and old heading
+     202           0 :       tf2::Matrix3x3 rot_mat = mrs_lib::AttitudeConverter(Eigen::AngleAxisd(hdg_mapping_old - hdg, Eigen::Vector3d::UnitZ()));
+     203             : 
+     204             :       // Transform the mavros orientation by the rotation matrix
+     205           0 :       geometry_msgs::Quaternion new_orientation = mrs_lib::AttitudeConverter(tf2::Transform(rot_mat) * tf2_rot);
+     206             : 
+     207             :       // Set new orientation
+     208           0 :       mapping_odom.pose.pose.orientation = new_orientation;
+     209             : 
+     210             : 
+     211             :       // Find corresponding local odom
+     212           0 :       double    odom_alt          = msg->pose.pose.position.z;  // start with newest msg
+     213           0 :       ros::Time dbg_timestamp_alt = msg->header.stamp;
+     214           0 :       for (size_t i = 0; i < vec_mapping_odom_alt_.size(); i++) {
+     215           0 :         if (mapping_odom.header.stamp < vec_mapping_odom_alt_.at(i).header.stamp) {
+     216             : 
+     217             :           // Choose orientation with closest timestamp
+     218           0 :           double time_diff      = std::fabs(vec_mapping_odom_alt_.at(i).header.stamp.toSec() - mapping_odom.header.stamp.toSec());
+     219           0 :           double time_diff_prev = std::numeric_limits<double>::max();
+     220           0 :           if (i > 0) {
+     221           0 :             time_diff_prev = std::fabs(vec_mapping_odom_alt_.at(i - 1).header.stamp.toSec() - mapping_odom.header.stamp.toSec());
+     222             :           }
+     223           0 :           if (time_diff_prev < time_diff && i > 0) {
+     224           0 :             i = i - 1;
+     225             :           }
+     226             :           // Cache is too small if it is full and its oldest element is used
+     227           0 :           if (clear_needed && i == 0) {
+     228           0 :             ROS_WARN_THROTTLE(1.0, "[%s] mapping orientation cache (for mapping tf) is too small.", getPrintName().c_str());
+     229             :           }
+     230           0 :           odom_alt          = vec_mapping_odom_alt_.at(i).pose.pose.position.z;
+     231           0 :           dbg_timestamp_alt = vec_mapping_odom_alt_.at(i).header.stamp;
+     232           0 :           break;
+     233             :         }
+     234             :       }
+     235             : 
+     236             :       // Set altitude
+     237           0 :       mapping_odom.pose.pose.position.z = odom_alt;
+     238             : 
+     239             :       // Get inverse transform
+     240           0 :       tf2::Transform      tf_mapping_inv   = Support::tf2FromPose(mapping_odom.pose.pose).inverse();
+     241           0 :       geometry_msgs::Pose pose_mapping_inv = Support::poseFromTf2(tf_mapping_inv);
+     242             : 
+     243           0 :       geometry_msgs::TransformStamped tf_mapping;
+     244           0 :       tf_mapping.header.stamp    = mapping_odom.header.stamp;
+     245           0 :       tf_mapping.header.frame_id = ch_->frames.ns_fcu;
+     246           0 :       if (custom_frame_id_enabled_) {
+     247           0 :         tf_mapping.child_frame_id = ch_->uav_name + "/" + custom_frame_id_;
+     248             :       } else {
+     249           0 :         tf_mapping.child_frame_id = mapping_odom.header.frame_id;
+     250             :       }
+     251           0 :       tf_mapping.transform.translation = Support::pointToVector3(pose_mapping_inv.position);
+     252           0 :       tf_mapping.transform.rotation    = pose_mapping_inv.orientation;
+     253             : 
+     254           0 :       if (Support::noNans(tf_mapping)) {
+     255             :         try {
+     256           0 :           broadcaster_->sendTransform(tf_mapping);
+     257             :         }
+     258           0 :         catch (...) {
+     259           0 :           ROS_ERROR("[%s]: Exception caught during publishing TF: %s - %s.", getPrintName().c_str(), tf_mapping.child_frame_id.c_str(),
+     260             :                     tf_mapping.header.frame_id.c_str());
+     261             :         }
+     262             :       } else {
+     263           0 :         ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_mapping.header.frame_id.c_str(),
+     264             :                           tf_mapping.child_frame_id.c_str());
+     265             :       }
+     266             : 
+     267             :       // debug timestamps: rot and alt timestamps should be as close as possible to lat_timestamp, the delay is the difference between current time and the time
+     268             :       // of acquisition of scan that was used to calculate the pose estimate
+     269           0 :       if (debug_prints_) {
+     270           0 :         ROS_INFO("[%s] lat timestamp: %.6f, rot stamp: %.6f (diff: %.6f),  alt stamp: %.6f (diff: %.6f), delay: %.6f", getPrintName().c_str(),
+     271             :                  mapping_odom.header.stamp.toSec(), dbg_timestamp_rot.toSec(), dbg_timestamp_rot.toSec() - mapping_odom.header.stamp.toSec(),
+     272             :                  dbg_timestamp_alt.toSec(), dbg_timestamp_alt.toSec() - mapping_odom.header.stamp.toSec(),
+     273             :                  ros::Time::now().toSec() - mapping_odom.header.stamp.toSec());
+     274             :       }
+     275             : 
+     276           0 :       mrs_msgs::Float64Stamped map_delay_msg;
+     277           0 :       map_delay_msg.header.stamp = ros::Time::now();
+     278           0 :       map_delay_msg.value        = ros::Time::now().toSec() - mapping_odom.header.stamp.toSec();
+     279           0 :       ph_map_delay_.publish(map_delay_msg);
+     280             :     }
+     281             : 
+     282             :     //}
+     283             :   }
+     284             :   /*//}*/
+     285             : 
+     286             :   std::string                                                 orientation_topic_;
+     287             :   mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped> sh_mapping_odom_rot_;
+     288             :   std::vector<geometry_msgs::QuaternionStamped>               vec_mapping_odom_rot_;
+     289             :   std::mutex                                                  mtx_mapping_odom_rot_;
+     290             :   std::atomic_bool                                            got_mapping_odom_rot_ = false;
+     291             : 
+     292             :   /*//{ callbackMappingOdomRot() */
+     293           0 :   void callbackMappingOdomRot(const geometry_msgs::QuaternionStamped::ConstPtr msg) {
+     294             : 
+     295           0 :     if (!is_initialized_) {
+     296           0 :       return;
+     297             :     }
+     298             : 
+     299           0 :     if (!got_mapping_odom_lat_) {
+     300           0 :       return;
+     301             :     }
+     302             : 
+     303           0 :     std::scoped_lock lock(mtx_mapping_odom_rot_);
+     304             : 
+     305             :     // Add new data
+     306           0 :     vec_mapping_odom_rot_.push_back(*msg);
+     307             : 
+     308             :     // Delete old data
+     309           0 :     size_t index_delete = 0;
+     310           0 :     bool   clear_needed = false;
+     311           0 :     for (size_t i = 0; i < vec_mapping_odom_rot_.size(); i++) {
+     312           0 :       if (timestamp_lat_ - vec_mapping_odom_rot_.at(i).header.stamp.toSec() > cache_duration_) {
+     313           0 :         index_delete = i;
+     314           0 :         clear_needed = true;
+     315             :       } else {
+     316           0 :         break;
+     317             :       }
+     318             :     }
+     319           0 :     if (clear_needed) {
+     320           0 :       for (int i = (int)index_delete; i >= 0; i--) {
+     321           0 :         vec_mapping_odom_rot_.erase(vec_mapping_odom_rot_.begin() + i);
+     322             :       }
+     323           0 :       clear_needed = false;
+     324             :     }
+     325             : 
+     326           0 :     if (!got_mapping_odom_rot_) {
+     327           0 :       got_mapping_odom_rot_ = true;
+     328             :     }
+     329             : 
+     330           0 :     if (debug_prints_) {
+     331           0 :       ROS_INFO_THROTTLE(1.0, "[%s]: mapping odom rot cache size: %lu", getPrintName().c_str(), vec_mapping_odom_rot_.size());
+     332             :     }
+     333             :   }
+     334             :   /*//}*/
+     335             : 
+     336             :   std::string                                   altitude_topic_;
+     337             :   mrs_lib::SubscribeHandler<nav_msgs::Odometry> sh_mapping_odom_alt_;
+     338             :   std::vector<nav_msgs::Odometry>               vec_mapping_odom_alt_;
+     339             :   std::mutex                                    mtx_mapping_odom_alt_;
+     340             :   std::atomic_bool                              got_mapping_odom_alt_ = false;
+     341             : 
+     342             :   /*//{ callbackMappingOdomAlt() */
+     343           0 :   void callbackMappingOdomAlt(const nav_msgs::Odometry::ConstPtr msg) {
+     344             : 
+     345           0 :     if (!is_initialized_) {
+     346           0 :       return;
+     347             :     }
+     348             : 
+     349           0 :     if (!got_mapping_odom_lat_) {
+     350           0 :       return;
+     351             :     }
+     352             : 
+     353           0 :     std::scoped_lock lock(mtx_mapping_odom_alt_);
+     354             : 
+     355             :     // Add new data
+     356           0 :     vec_mapping_odom_alt_.push_back(*msg);
+     357             : 
+     358             :     // Delete old data
+     359           0 :     size_t index_delete = 0;
+     360           0 :     bool   clear_needed = false;
+     361           0 :     for (size_t i = 0; i < vec_mapping_odom_alt_.size(); i++) {
+     362           0 :       if (timestamp_lat_ - vec_mapping_odom_alt_.at(i).header.stamp.toSec() > cache_duration_) {
+     363           0 :         index_delete = i;
+     364           0 :         clear_needed = true;
+     365             :       } else {
+     366           0 :         break;
+     367             :       }
+     368             :     }
+     369           0 :     if (clear_needed) {
+     370           0 :       for (int i = (int)index_delete; i >= 0; i--) {
+     371           0 :         vec_mapping_odom_alt_.erase(vec_mapping_odom_alt_.begin() + i);
+     372             :       }
+     373           0 :       clear_needed = false;
+     374             :     }
+     375             : 
+     376           0 :     if (!got_mapping_odom_alt_) {
+     377           0 :       got_mapping_odom_alt_ = true;
+     378             :     }
+     379             : 
+     380           0 :     if (debug_prints_) {
+     381           0 :       ROS_INFO_THROTTLE(1.0, "[%s]: mapping odom alt cache size: %lu", getPrintName().c_str(), vec_mapping_odom_alt_.size());
+     382             :     }
+     383             :   }
+     384             :   /*//}*/
+     385             : };
+     386             : /*//}*/
+     387             : 
+     388             : }  // namespace mrs_uav_managers
+     389             : 
+     390             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/tf_source.h.func-sort-c.html b/mrs_uav_managers/include/transform_manager/tf_source.h.func-sort-c.html new file mode 100644 index 0000000000..eeec5eb89f --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/tf_source.h.func-sort-c.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager/tf_source.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_manager - tf_source.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:18623778.5 %
Date:2023-11-29 14:09:54Functions:111478.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers8TfSource13getIsUtmBasedEv0
_ZN16mrs_uav_managers8TfSource14getIsUtmSourceEv0
_ZN16mrs_uav_managers8TfSource14setIsUtmSourceEb0
_ZN16mrs_uav_managers8TfSource12setUtmOriginERKN13geometry_msgs6Point_ISaIvEEE7
_ZN16mrs_uav_managers8TfSource14publishLocalTfERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
_ZN16mrs_uav_managers8TfSource14setWorldOriginERKN13geometry_msgs6Point_ISaIvEEE7
_ZN16mrs_uav_managers8TfSourceC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEN3ros10NodeHandleESt10shared_ptrIN7mrs_lib11ParamLoaderEERKSB_INSC_20TransformBroadcasterEESB_INS_18estimation_manager16CommonHandlers_tEEb7
_ZN16mrs_uav_managers8TfSource7getNameB5cxx11Ev53
_ZN16mrs_uav_managers8TfSource16republishInFrameERKN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN7mrs_lib16PublisherHandlerIS6_EE4162
_ZN16mrs_uav_managers8TfSource16publishTfFromAttERKN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE5514
_ZN16mrs_uav_managers8TfSource19callbackTfSourceAttEN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE5514
_ZN16mrs_uav_managers8TfSource17publishTfFromOdomERKN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE9676
_ZN16mrs_uav_managers8TfSource20callbackTfSourceOdomEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE9676
_ZN16mrs_uav_managers8TfSource12getPrintNameB5cxx11Ev34447
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/tf_source.h.func.html b/mrs_uav_managers/include/transform_manager/tf_source.h.func.html new file mode 100644 index 0000000000..197e350958 --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/tf_source.h.func.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager/tf_source.h - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_manager - tf_source.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:18623778.5 %
Date:2023-11-29 14:09:54Functions:111478.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers8TfSource12getPrintNameB5cxx11Ev34447
_ZN16mrs_uav_managers8TfSource12setUtmOriginERKN13geometry_msgs6Point_ISaIvEEE7
_ZN16mrs_uav_managers8TfSource13getIsUtmBasedEv0
_ZN16mrs_uav_managers8TfSource14getIsUtmSourceEv0
_ZN16mrs_uav_managers8TfSource14publishLocalTfERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
_ZN16mrs_uav_managers8TfSource14setIsUtmSourceEb0
_ZN16mrs_uav_managers8TfSource14setWorldOriginERKN13geometry_msgs6Point_ISaIvEEE7
_ZN16mrs_uav_managers8TfSource16publishTfFromAttERKN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE5514
_ZN16mrs_uav_managers8TfSource16republishInFrameERKN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERN7mrs_lib16PublisherHandlerIS6_EE4162
_ZN16mrs_uav_managers8TfSource17publishTfFromOdomERKN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE9676
_ZN16mrs_uav_managers8TfSource19callbackTfSourceAttEN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE5514
_ZN16mrs_uav_managers8TfSource20callbackTfSourceOdomEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE9676
_ZN16mrs_uav_managers8TfSource7getNameB5cxx11Ev53
_ZN16mrs_uav_managers8TfSourceC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEN3ros10NodeHandleESt10shared_ptrIN7mrs_lib11ParamLoaderEERKSB_INSC_20TransformBroadcasterEESB_INS_18estimation_manager16CommonHandlers_tEEb7
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/include/transform_manager/tf_source.h.gcov.html b/mrs_uav_managers/include/transform_manager/tf_source.h.gcov.html new file mode 100644 index 0000000000..b331e388e8 --- /dev/null +++ b/mrs_uav_managers/include/transform_manager/tf_source.h.gcov.html @@ -0,0 +1,693 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/include/transform_manager/tf_source.h + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/include/transform_manager - tf_source.h (source / functions)HitTotalCoverage
Test:coverage.infoLines:18623778.5 %
Date:2023-11-29 14:09:54Functions:111478.6 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #pragma once
+       2             : #ifndef TF_SOURCE_H
+       3             : #define TF_SOURCE_H
+       4             : 
+       5             : #include <ros/ros.h>
+       6             : 
+       7             : #include <mrs_lib/param_loader.h>
+       8             : #include <mrs_lib/subscribe_handler.h>
+       9             : #include <mrs_lib/publisher_handler.h>
+      10             : #include <mrs_lib/attitude_converter.h>
+      11             : #include <mrs_lib/transformer.h>
+      12             : #include <mrs_lib/transform_broadcaster.h>
+      13             : #include <mrs_lib/gps_conversions.h>
+      14             : 
+      15             : #include <tf2_ros/transform_broadcaster.h>
+      16             : #include <tf2_ros/static_transform_broadcaster.h>
+      17             : 
+      18             : #include <geometry_msgs/TransformStamped.h>
+      19             : 
+      20             : #include <nav_msgs/Odometry.h>
+      21             : 
+      22             : #include <memory>
+      23             : #include <string>
+      24             : 
+      25             : #include <mrs_uav_managers/estimation_manager/support.h>
+      26             : #include <mrs_uav_managers/estimation_manager/common_handlers.h>
+      27             : 
+      28             : namespace mrs_uav_managers
+      29             : {
+      30             : 
+      31             : /*//{ class TfSource */
+      32             : class TfSource {
+      33             : 
+      34             :   using Support = estimation_manager::Support;
+      35             : 
+      36             : public:
+      37             :   /*//{ constructor */
+      38           7 :   TfSource(const std::string& name, ros::NodeHandle nh, std::shared_ptr<mrs_lib::ParamLoader> param_loader,
+      39             :            const std::shared_ptr<mrs_lib::TransformBroadcaster>& broadcaster, const std::shared_ptr<estimation_manager::CommonHandlers_t> ch,
+      40             :            const bool is_utm_source)
+      41           7 :       : name_(name), nh_(nh), broadcaster_(broadcaster), ch_(ch), is_utm_source_(is_utm_source) {
+      42             : 
+      43           7 :     ROS_INFO("[%s]: initializing", getPrintName().c_str());
+      44             : 
+      45           7 :     if (name != "dummy") {
+      46             : 
+      47             :       /*//{ load parameters */
+      48             : 
+      49          14 :       const std::string yaml_prefix = "mrs_uav_managers/transform_manager/";
+      50             : 
+      51          14 :       std::string odom_topic, attitude_topic, ns;
+      52             : 
+      53           7 :       param_loader->loadParam(yaml_prefix + getName() + "/odom_topic", odom_topic);
+      54           7 :       param_loader->loadParam(yaml_prefix + getName() + "/custom_frame_id/enabled", custom_frame_id_enabled_, false);
+      55           7 :       if (custom_frame_id_enabled_) {
+      56           0 :         param_loader->loadParam(yaml_prefix + getName() + "/custom_frame_id/frame_id", custom_frame_id_);
+      57             :       }
+      58           7 :       param_loader->loadParam(yaml_prefix + getName() + "/tf_from_attitude/enabled", tf_from_attitude_enabled_);
+      59           7 :       if (tf_from_attitude_enabled_) {
+      60           4 :         param_loader->loadParam(yaml_prefix + getName() + "/tf_from_attitude/attitude_topic", attitude_topic);
+      61             :       }
+      62           7 :       param_loader->loadParam(yaml_prefix + getName() + "/namespace", ns);
+      63           7 :       full_topic_odom_     = "/" + ch_->uav_name + "/" + ns + "/" + odom_topic;
+      64           7 :       full_topic_attitude_ = "/" + ch_->uav_name + "/" + ns + "/" + attitude_topic;
+      65           7 :       param_loader->loadParam(yaml_prefix + getName() + "/inverted", is_inverted_);
+      66           7 :       param_loader->loadParam(yaml_prefix + getName() + "/republish_in_frames", republish_in_frames_);
+      67             : 
+      68             :       /* coordinate frames origins //{ */
+      69           7 :       param_loader->loadParam(yaml_prefix + getName() + "/utm_based", is_utm_based_);
+      70             :       /* param_loader->loadParam(yaml_prefix + getName() + "/publish_local_tf", publish_local_tf_); */
+      71             : 
+      72             :       /*//{ utm source */
+      73           7 :       if (is_utm_based_) {
+      74           8 :         std::string utm_origin_parent_frame_id;
+      75           4 :         param_loader->loadParam(yaml_prefix + "utm_origin_tf/parent", utm_origin_parent_frame_id);
+      76           4 :         ns_utm_origin_parent_frame_id_ = ch_->uav_name + "/" + utm_origin_parent_frame_id;
+      77             : 
+      78           4 :         std::string utm_origin_child_frame_id;
+      79           4 :         param_loader->loadParam(yaml_prefix + "utm_origin_tf/child", utm_origin_child_frame_id);
+      80           4 :         ns_utm_origin_child_frame_id_ = ch_->uav_name + "/" + utm_origin_child_frame_id;
+      81             :       }
+      82             :       /*//}*/
+      83             : 
+      84             :       /*//{ world source */
+      85           7 :       if (is_utm_based_) {
+      86           8 :         std::string world_origin_parent_frame_id;
+      87           4 :         param_loader->loadParam(yaml_prefix + "world_origin_tf/parent", world_origin_parent_frame_id);
+      88           4 :         ns_world_origin_parent_frame_id_ = ch_->uav_name + "/" + world_origin_parent_frame_id;
+      89             : 
+      90           4 :         std::string world_origin_child_frame_id;
+      91           4 :         param_loader->loadParam(yaml_prefix + "world_origin_tf/child", world_origin_child_frame_id);
+      92           4 :         ns_world_origin_child_frame_id_ = ch_->uav_name + "/" + world_origin_child_frame_id;
+      93             :       }
+      94             :       /*//}*/
+      95             : 
+      96             :       //}
+      97             : 
+      98           7 :       if (!param_loader->loadedSuccessfully()) {
+      99           0 :         ROS_ERROR("[%s]: Could not load all non-optional parameters. Shutting down.", getPrintName().c_str());
+     100           0 :         ros::shutdown();
+     101             :       }
+     102             : 
+     103             :       /*//}*/
+     104             : 
+     105             :       /*//{ initialize subscribers */
+     106          14 :       mrs_lib::SubscribeHandlerOptions shopts;
+     107           7 :       shopts.nh                 = nh_;
+     108           7 :       shopts.node_name          = getPrintName();
+     109           7 :       shopts.no_message_timeout = mrs_lib::no_timeout;
+     110           7 :       shopts.threadsafe         = true;
+     111           7 :       shopts.autostart          = true;
+     112           7 :       shopts.queue_size         = 10;
+     113           7 :       shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     114             : 
+     115           7 :       sh_tf_source_odom_ = mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, full_topic_odom_, &TfSource::callbackTfSourceOdom, this);
+     116           7 :       if (tf_from_attitude_enabled_) {
+     117           4 :         sh_tf_source_att_ = mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped>(shopts, full_topic_attitude_, &TfSource::callbackTfSourceAtt, this);
+     118             :       }
+     119             : 
+     120           7 :       if (is_utm_source_) {
+     121           4 :         sh_altitude_amsl_ = mrs_lib::SubscribeHandler<mrs_msgs::HwApiAltitude>(shopts, "altitude_amsl_in");
+     122             :       }
+     123             : 
+     124             :     }
+     125             :     /*//}*/
+     126             : 
+     127          10 :     for (auto frame_id : republish_in_frames_) {
+     128           3 :       republishers_.push_back(
+     129           6 :           std::make_pair(frame_id, mrs_lib::PublisherHandler<nav_msgs::Odometry>(nh_, full_topic_odom_ + "/" + frame_id.substr(0, frame_id.find("_origin")))));
+     130             :     }
+     131           7 :     is_initialized_ = true;
+     132           7 :     ROS_INFO("[%s]: initialized", getPrintName().c_str());
+     133           7 :   }
+     134             :   /*//}*/
+     135             : 
+     136             :   /*//{ getName() */
+     137          53 :   std::string getName() {
+     138          53 :     return name_;
+     139             :   }
+     140             :   /*//}*/
+     141             : 
+     142             :   /*//{ getPrintName() */
+     143       34447 :   std::string getPrintName() {
+     144       68955 :     return ch_->nodelet_name + "/" + name_;
+     145             :   }
+     146             :   /*//}*/
+     147             : 
+     148             :   /*//{ getIsUtmBased() */
+     149           0 :   bool getIsUtmBased() {
+     150           0 :     return is_utm_based_;
+     151             :   }
+     152             :   /*//}*/
+     153             : 
+     154             :   /*//{ getIsUtmSource() */
+     155           0 :   bool getIsUtmSource() {
+     156           0 :     return is_utm_source_;
+     157             :   }
+     158             :   /*//}*/
+     159             : 
+     160             :   /*//{ setIsUtmSource() */
+     161           0 :   void setIsUtmSource(const bool is_utm_source) {
+     162           0 :     if (is_utm_source) {
+     163           0 :       mrs_lib::SubscribeHandlerOptions shopts;
+     164           0 :       shopts.nh                 = nh_;
+     165           0 :       shopts.node_name          = getPrintName();
+     166           0 :       shopts.no_message_timeout = mrs_lib::no_timeout;
+     167           0 :       shopts.threadsafe         = true;
+     168           0 :       shopts.autostart          = true;
+     169           0 :       shopts.queue_size         = 10;
+     170           0 :       shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     171           0 :       sh_altitude_amsl_ = mrs_lib::SubscribeHandler<mrs_msgs::HwApiAltitude>(shopts, "altitude_amsl_in");
+     172             :     }
+     173           0 :     is_utm_source_ = is_utm_source;
+     174           0 :   }
+     175             :   /*//}*/
+     176             : 
+     177             :   /*//{ setUtmOrigin() */
+     178           7 :   void setUtmOrigin(const geometry_msgs::Point& pt) {
+     179             : 
+     180           7 :     if (is_utm_based_ && !is_utm_origin_set_) {
+     181           4 :       utm_origin_        = pt;
+     182           4 :       is_utm_origin_set_ = true;
+     183             :     }
+     184           7 :   }
+     185             :   /*//}*/
+     186             : 
+     187             :   /*//{ setWorldOrigin() */
+     188           7 :   void setWorldOrigin(const geometry_msgs::Point& pt) {
+     189             : 
+     190           7 :     if (is_utm_based_ && !is_world_origin_set_) {
+     191           4 :       world_origin_        = pt;
+     192           4 :       is_world_origin_set_ = true;
+     193             :     }
+     194           7 :   }
+     195             :   /*//}*/
+     196             : 
+     197             : private:
+     198             :   const std::string name_;
+     199             :   const std::string ns_fcu_frame_id_;
+     200             : 
+     201             :   ros::NodeHandle nh_;
+     202             : 
+     203             :   std::shared_ptr<mrs_lib::TransformBroadcaster> broadcaster_;
+     204             :   tf2_ros::StaticTransformBroadcaster            static_broadcaster_;
+     205             : 
+     206             :   std::shared_ptr<estimation_manager::CommonHandlers_t> ch_;
+     207             : 
+     208             :   bool is_inverted_;
+     209             : 
+     210             :   bool             is_utm_based_;
+     211             :   bool             publish_local_tf_ = true;
+     212             :   bool             publish_utm_tf_   = false;
+     213             :   bool             publish_world_tf_ = false;
+     214             :   std::atomic_bool is_utm_source_    = false;
+     215             :   std::string      ns_utm_origin_parent_frame_id_;
+     216             :   std::string      ns_utm_origin_child_frame_id_;
+     217             : 
+     218             :   bool                 is_utm_origin_set_ = false;
+     219             :   geometry_msgs::Point utm_origin_;
+     220             : 
+     221             :   std::string ns_world_origin_parent_frame_id_;
+     222             :   std::string ns_world_origin_child_frame_id_;
+     223             : 
+     224             :   bool                 is_world_origin_set_ = false;
+     225             :   geometry_msgs::Point world_origin_;
+     226             : 
+     227             :   std::string full_topic_odom_;
+     228             :   std::string full_topic_attitude_;
+     229             :   bool        tf_from_attitude_enabled_ = false;
+     230             : 
+     231             :   bool        custom_frame_id_enabled_;
+     232             :   std::string custom_frame_id_;
+     233             : 
+     234             :   std::atomic_bool is_initialized_               = false;
+     235             :   std::atomic_bool is_local_static_tf_published_ = false;
+     236             :   std::atomic_bool is_utm_static_tf_published_   = false;
+     237             :   std::atomic_bool is_world_static_tf_published_ = false;
+     238             : 
+     239             :   std::vector<std::string> republish_in_frames_;
+     240             : 
+     241             :   std::vector<std::pair<std::string, mrs_lib::PublisherHandler<nav_msgs::Odometry>>> republishers_;
+     242             : 
+     243             :   mrs_lib::SubscribeHandler<nav_msgs::Odometry>               sh_tf_source_odom_;
+     244             :   mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped> sh_tf_source_att_;
+     245             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiAltitude>          sh_altitude_amsl_;
+     246             :   nav_msgs::OdometryConstPtr                                  first_msg_;
+     247             :   bool                                                        got_first_msg_ = false;
+     248             : 
+     249             : 
+     250             :   /*//{ callbackTfSourceOdom()*/
+     251        9676 :   void callbackTfSourceOdom(const nav_msgs::Odometry::ConstPtr msg) {
+     252             : 
+     253        9676 :     if (!is_initialized_) {
+     254           0 :       return;
+     255             :     }
+     256             : 
+     257       29028 :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::callbackTfSourceOdom", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     258             : 
+     259        9676 :     scope_timer.checkpoint("get msg");
+     260             : 
+     261        9676 :     if (!got_first_msg_) {
+     262           7 :       first_msg_     = msg;
+     263           7 :       got_first_msg_ = true;
+     264             :     }
+     265             : 
+     266        9676 :     publishTfFromOdom(msg);
+     267        9676 :     scope_timer.checkpoint("pub tf");
+     268             : 
+     269        9676 :     if (publish_local_tf_ && !is_local_static_tf_published_) {
+     270           7 :       publishLocalTf(msg->header.frame_id);
+     271           7 :       scope_timer.checkpoint("pub local tf");
+     272             :     }
+     273             : 
+     274             :     /* if (publish_utm_tf_ && is_utm_based_ && is_utm_origin_set_ && !is_utm_static_tf_published_) { */
+     275             :     /*   publishUtmTf(msg->header.frame_id); */
+     276             :     /*   scope_timer.checkpoint("pub utm tf"); */
+     277             :     /* } */
+     278             : 
+     279             :     /* if (publish_world_tf_ && is_utm_based_ && is_world_origin_set_ && !is_world_static_tf_published_) { */
+     280             :     /*   publishWorldTf(msg->header.frame_id); */
+     281             :     /*   scope_timer.checkpoint("pub world tf"); */
+     282             :     /* } */
+     283             : 
+     284       13838 :     for (auto republisher : republishers_) {
+     285        4162 :       republishInFrame(msg, ch_->uav_name + "/" + republisher.first, republisher.second);
+     286             :     }
+     287             :   }
+     288             :   /*//}*/
+     289             : 
+     290             :   /*//{ callbackTfSourceAtt()*/
+     291        5514 :   void callbackTfSourceAtt(const geometry_msgs::QuaternionStamped::ConstPtr msg) {
+     292             : 
+     293        5514 :     if (!is_initialized_) {
+     294           0 :       return;
+     295             :     }
+     296             : 
+     297       16542 :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::callbackTfSourceAtt", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     298             : 
+     299        5514 :     scope_timer.checkpoint("get msg");
+     300        5514 :     publishTfFromAtt(msg);
+     301             :   }
+     302             :   /*//}*/
+     303             : 
+     304             :   /* publishTfFromOdom() //{*/
+     305        9676 :   void publishTfFromOdom(const nav_msgs::OdometryConstPtr& odom) {
+     306             : 
+     307       19352 :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::publishTfFromOdom", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     308             : 
+     309        9676 :     const tf2::Transform      tf       = Support::tf2FromPose(odom->pose.pose);
+     310        9676 :     const tf2::Transform      tf_inv   = tf.inverse();
+     311        9676 :     const geometry_msgs::Pose pose_inv = Support::poseFromTf2(tf_inv);
+     312             : 
+     313             :     /*//{ tf source origin */
+     314        9676 :     geometry_msgs::TransformStamped tf_msg;
+     315        9676 :     tf_msg.header.stamp         = odom->header.stamp;
+     316        9676 :     std::string origin_frame_id = custom_frame_id_enabled_ ? ch_->uav_name + "/" + custom_frame_id_ : odom->header.frame_id;
+     317        9676 :     if (is_inverted_) {
+     318             : 
+     319        9676 :       tf_msg.header.frame_id       = ch_->frames.ns_fcu;
+     320        9676 :       tf_msg.child_frame_id        = origin_frame_id;
+     321        9676 :       tf_msg.transform.translation = Support::pointToVector3(pose_inv.position);
+     322        9676 :       tf_msg.transform.rotation    = pose_inv.orientation;
+     323             : 
+     324             :     } else {
+     325           0 :       tf_msg.header.frame_id       = origin_frame_id;
+     326           0 :       tf_msg.child_frame_id        = ch_->frames.ns_fcu;
+     327           0 :       tf_msg.transform.translation = Support::pointToVector3(odom->pose.pose.position);
+     328           0 :       tf_msg.transform.rotation    = odom->pose.pose.orientation;
+     329             :     }
+     330             : 
+     331        9676 :     if (Support::noNans(tf_msg)) {
+     332             :       try {
+     333        9676 :         broadcaster_->sendTransform(tf_msg);
+     334             :       }
+     335           0 :       catch (...) {
+     336           0 :         ROS_ERROR("exception caught ");
+     337             :       }
+     338             : 
+     339        9676 :       if (tf_from_attitude_enabled_) {
+     340        5514 :         if (is_inverted_) {
+     341        5514 :           tf_msg.child_frame_id += "_att_only";
+     342             :         } else {
+     343           0 :           tf_msg.header.frame_id += "_att_only";
+     344             :         }
+     345             :         try {
+     346        5514 :           broadcaster_->sendTransform(tf_msg);
+     347             :         }
+     348           0 :         catch (...) {
+     349           0 :           ROS_ERROR("exception caught ");
+     350             :         }
+     351             :       }
+     352             :       /*//}*/
+     353             : 
+     354             :       /*//{ tf utm origin */
+     355             : 
+     356        9676 :       geometry_msgs::TransformStamped tf_utm_msg;
+     357        9676 :       if (is_utm_source_) {
+     358             :         
+     359        5514 :         if (!is_utm_origin_set_) {
+     360           0 :           ROS_INFO_THROTTLE(5.0, "[%s]: %s utm_origin initialization", getPrintName().c_str(), Support::waiting_for_string.c_str());
+     361           0 :           return;
+     362             :         }
+     363             : 
+     364        5514 :         geometry_msgs::Pose pose_utm = odom->pose.pose;
+     365        5514 :         pose_utm.position.x += utm_origin_.x - first_msg_->pose.pose.position.x;
+     366        5514 :         pose_utm.position.y += utm_origin_.y - first_msg_->pose.pose.position.y;
+     367             : 
+     368        5514 :         if (sh_altitude_amsl_.hasMsg()) {
+     369        5514 :           pose_utm.position.z = sh_altitude_amsl_.getMsg()->amsl;
+     370             :         } else {
+     371           0 :           ROS_WARN_THROTTLE(5.0, "[%s]: AMSL altitude not available.", getPrintName().c_str());
+     372             :         }
+     373             : 
+     374        5514 :         tf_utm_msg.header.stamp    = odom->header.stamp;
+     375        5514 :         tf_utm_msg.header.frame_id = ns_utm_origin_parent_frame_id_;
+     376        5514 :         tf_utm_msg.child_frame_id  = ns_utm_origin_child_frame_id_;
+     377             : 
+     378        5514 :         tf2::Transform tf_utm;
+     379        5514 :         if (is_inverted_) {
+     380        5514 :           tf_utm = Support::tf2FromPose(pose_utm).inverse();
+     381             :         } else {
+     382           0 :           tf_utm = Support::tf2FromPose(pose_utm);
+     383             :         }
+     384        5514 :         tf_utm_msg.transform = Support::msgFromTf2(tf_utm);
+     385             : 
+     386             :         try {
+     387        5514 :           broadcaster_->sendTransform(tf_utm_msg);
+     388        5514 :           ROS_INFO_ONCE("[%s]: publishing utm_origin tf", getPrintName().c_str());
+     389             :         }
+     390           0 :         catch (...) {
+     391           0 :           ROS_ERROR("exception caught ");
+     392             :         }
+     393             :       }
+     394             :       /*//}*/
+     395             : 
+     396             :       /*//{ tf world origin */
+     397        9676 :       if (is_utm_source_) {
+     398       11028 :         geometry_msgs::TransformStamped tf_world_msg;
+     399        5514 :         tf_world_msg.header.stamp    = odom->header.stamp;
+     400        5514 :         tf_world_msg.header.frame_id = ns_world_origin_parent_frame_id_;
+     401        5514 :         tf_world_msg.child_frame_id  = ns_world_origin_child_frame_id_;
+     402             : 
+     403        5514 :         tf2::Transform tf_world;
+     404        5514 :         tf_world.setOrigin(tf2::Vector3(world_origin_.x, world_origin_.y, world_origin_.z));
+     405        5514 :         tf_world.setRotation(tf2::Quaternion(0, 0, 0, 1));
+     406             : 
+     407        5514 :         geometry_msgs::Pose pose_utm = odom->pose.pose;
+     408        5514 :         pose_utm.position.x += utm_origin_.x - first_msg_->pose.pose.position.x;
+     409        5514 :         pose_utm.position.y += utm_origin_.y - first_msg_->pose.pose.position.y;
+     410             : 
+     411        5514 :         tf2::Transform tf_utm;
+     412        5514 :         if (is_inverted_) {
+     413        5514 :           tf_utm = Support::tf2FromPose(pose_utm).inverse();
+     414             :         } else {
+     415           0 :           tf_utm = Support::tf2FromPose(pose_utm);
+     416             :         }
+     417             : 
+     418        5514 :         tf_world_msg.transform          = Support::msgFromTf2(tf_utm * tf_world);
+     419        5514 :         tf_world_msg.transform.rotation = pose_inv.orientation;
+     420             : 
+     421             :         try {
+     422        5514 :           broadcaster_->sendTransform(tf_world_msg);
+     423        5514 :           ROS_INFO_ONCE("[%s]: publishing world_origin tf", getPrintName().c_str());
+     424             :         }
+     425           0 :         catch (...) {
+     426           0 :           ROS_ERROR("exception caught ");
+     427             :         }
+     428             :       }
+     429             : 
+     430             :       /*//}*/
+     431             : 
+     432             :     } else {
+     433           0 :       ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     434             :                         tf_msg.child_frame_id.c_str());
+     435             :     }
+     436        9676 :     ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s based on topic: %s", getPrintName().c_str(),
+     437             :                   tf_msg.header.frame_id.c_str(), tf_msg.child_frame_id.c_str(), full_topic_odom_.c_str());
+     438             :   }
+     439             :   /*//}*/
+     440             : 
+     441             :   /* publishTfFromAtt() //{*/
+     442        5514 :   void publishTfFromAtt(const geometry_msgs::QuaternionStampedConstPtr& msg) {
+     443             : 
+     444       16542 :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::publishTfFromAtt", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     445             : 
+     446       11028 :     geometry_msgs::TransformStamped tf_msg;
+     447        5514 :     tf_msg.header.stamp = msg->header.stamp;
+     448             : 
+     449        5514 :     geometry_msgs::Pose pose;
+     450        5514 :     pose.orientation = msg->quaternion;
+     451        5514 :     if (is_inverted_) {
+     452             : 
+     453        5514 :       const tf2::Transform      tf       = Support::tf2FromPose(pose);
+     454        5514 :       const tf2::Transform      tf_inv   = tf.inverse();
+     455        5514 :       const geometry_msgs::Pose pose_inv = Support::poseFromTf2(tf_inv);
+     456             : 
+     457        5514 :       tf_msg.header.frame_id       = ch_->frames.ns_fcu;
+     458        5514 :       tf_msg.child_frame_id        = msg->header.frame_id;
+     459        5514 :       tf_msg.transform.translation = Support::pointToVector3(pose_inv.position);
+     460        5514 :       tf_msg.transform.rotation    = pose_inv.orientation;
+     461             : 
+     462             :     } else {
+     463           0 :       tf_msg.header.frame_id       = msg->header.frame_id;
+     464           0 :       tf_msg.child_frame_id        = ch_->frames.ns_fcu;
+     465           0 :       tf_msg.transform.translation = Support::pointToVector3(pose.position);
+     466           0 :       tf_msg.transform.rotation    = pose.orientation;
+     467             :     }
+     468             : 
+     469        5514 :     if (Support::noNans(tf_msg)) {
+     470             :       try {
+     471        5514 :         scope_timer.checkpoint("before pub");
+     472        5514 :         broadcaster_->sendTransform(tf_msg);
+     473        5514 :         scope_timer.checkpoint("after pub");
+     474             :       }
+     475           0 :       catch (...) {
+     476           0 :         ROS_ERROR("exception caught ");
+     477             :       }
+     478             :     } else {
+     479           0 :       ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     480             :                         tf_msg.child_frame_id.c_str());
+     481             :     }
+     482        5514 :     ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s based on topic: %s", getPrintName().c_str(),
+     483             :                   tf_msg.header.frame_id.c_str(), tf_msg.child_frame_id.c_str(), full_topic_attitude_.c_str());
+     484        5514 :   }
+     485             :   /*//}*/
+     486             : 
+     487             :   /* publishLocalTf() //{*/
+     488           7 :   void publishLocalTf(const std::string& frame_id) {
+     489             : 
+     490          21 :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::publishLocalTf", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     491             : 
+     492          14 :     geometry_msgs::TransformStamped tf_msg;
+     493           7 :     tf_msg.header.stamp = ros::Time::now();
+     494             : 
+     495           7 :     tf_msg.header.frame_id       = frame_id;
+     496           7 :     tf_msg.child_frame_id        = frame_id.substr(0, frame_id.find("_origin")) + "_local_origin";
+     497           7 :     tf_msg.transform.translation = Support::pointToVector3(first_msg_->pose.pose.position);
+     498           7 :     tf_msg.transform.rotation    = first_msg_->pose.pose.orientation;
+     499             : 
+     500           7 :     if (Support::noNans(tf_msg)) {
+     501             :       try {
+     502           7 :         static_broadcaster_.sendTransform(tf_msg);
+     503             :       }
+     504           0 :       catch (...) {
+     505           0 :         ROS_ERROR("exception caught ");
+     506             :       }
+     507             :     } else {
+     508           0 :       ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     509             :                         tf_msg.child_frame_id.c_str());
+     510             :     }
+     511           7 :     ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s based on first message of: %s", getPrintName().c_str(),
+     512             :                   tf_msg.header.frame_id.c_str(), tf_msg.child_frame_id.c_str(), full_topic_odom_.c_str());
+     513           7 :     is_local_static_tf_published_ = true;
+     514           7 :   }
+     515             :   /*//}*/
+     516             : 
+     517             :   /* publishUtmTf() //{*/
+     518             :   void publishUtmTf(const std::string& frame_id) {
+     519             : 
+     520             :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::publishUtmTf", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     521             : 
+     522             :     geometry_msgs::TransformStamped tf_msg;
+     523             :     tf_msg.header.stamp = ros::Time::now();
+     524             : 
+     525             :     tf_msg.header.frame_id         = frame_id;
+     526             :     tf_msg.child_frame_id          = frame_id.substr(0, frame_id.find("_origin")) + "_utm_origin";
+     527             :     tf_msg.transform.translation.x = -utm_origin_.x;  // minus because inverse tf tree
+     528             :     tf_msg.transform.translation.y = -utm_origin_.y;  // minus because inverse tf tree
+     529             :     tf_msg.transform.translation.z = -utm_origin_.z;  // minus because inverse tf tree
+     530             :     tf_msg.transform.rotation.x    = 0;
+     531             :     tf_msg.transform.rotation.y    = 0;
+     532             :     tf_msg.transform.rotation.z    = 0;
+     533             :     tf_msg.transform.rotation.w    = 1;
+     534             : 
+     535             :     if (Support::noNans(tf_msg)) {
+     536             :       try {
+     537             :         static_broadcaster_.sendTransform(tf_msg);
+     538             :       }
+     539             :       catch (...) {
+     540             :         ROS_ERROR("exception caught ");
+     541             :       }
+     542             :     } else {
+     543             :       ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     544             :                         tf_msg.child_frame_id.c_str());
+     545             :     }
+     546             :     ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s based on first message of: %s", getPrintName().c_str(),
+     547             :                   tf_msg.header.frame_id.c_str(), tf_msg.child_frame_id.c_str(), full_topic_odom_.c_str());
+     548             :     is_utm_static_tf_published_ = true;
+     549             :   }
+     550             :   /*//}*/
+     551             : 
+     552             :   /* publishWorldTf() //{*/
+     553             :   void publishWorldTf(const std::string& frame_id) {
+     554             : 
+     555             :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::publishWorldTf", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     556             : 
+     557             :     geometry_msgs::TransformStamped tf_msg;
+     558             :     tf_msg.header.stamp = ros::Time::now();
+     559             : 
+     560             :     tf_msg.header.frame_id         = frame_id;
+     561             :     tf_msg.child_frame_id          = frame_id.substr(0, frame_id.find("_origin")) + "_world_origin";
+     562             :     tf_msg.transform.translation.x = -(utm_origin_.x - world_origin_.x);  // minus because inverse tf tree
+     563             :     tf_msg.transform.translation.y = -(utm_origin_.y - world_origin_.y);  // minus because inverse tf tree
+     564             :     /* tf_msg.transform.translation.z = -(utm_origin_.z);                    // minus because inverse tf tree */
+     565             :     tf_msg.transform.translation.z = 0;
+     566             :     tf_msg.transform.rotation.x    = 0;
+     567             :     tf_msg.transform.rotation.y    = 0;
+     568             :     tf_msg.transform.rotation.z    = 0;
+     569             :     tf_msg.transform.rotation.w    = 1;
+     570             : 
+     571             :     if (Support::noNans(tf_msg)) {
+     572             :       try {
+     573             :         static_broadcaster_.sendTransform(tf_msg);
+     574             :       }
+     575             :       catch (...) {
+     576             :         ROS_ERROR("exception caught ");
+     577             :       }
+     578             :     } else {
+     579             :       ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     580             :                         tf_msg.child_frame_id.c_str());
+     581             :     }
+     582             :     ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s based on first message of: %s", getPrintName().c_str(),
+     583             :                   tf_msg.header.frame_id.c_str(), tf_msg.child_frame_id.c_str(), full_topic_odom_.c_str());
+     584             :     is_world_static_tf_published_ = true;
+     585             :   }
+     586             :   /*//}*/
+     587             : 
+     588             :   /* republishInFrame() //{*/
+     589        4162 :   void republishInFrame(const nav_msgs::OdometryConstPtr& msg, const std::string& frame_id, mrs_lib::PublisherHandler<nav_msgs::Odometry>& ph) {
+     590             : 
+     591        8324 :     mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer(getPrintName() + "::republishInFrame", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     592             : 
+     593        4162 :     nav_msgs::Odometry msg_out = *msg;
+     594        4162 :     msg_out.header.frame_id    = frame_id;
+     595             : 
+     596        4162 :     geometry_msgs::PoseStamped pose;
+     597        4162 :     pose.header = msg->header;
+     598        4162 :     pose.pose   = msg->pose.pose;
+     599             : 
+     600        4162 :     auto res = ch_->transformer->transformSingle(pose, frame_id);
+     601        4162 :     if (res) {
+     602        4156 :       msg_out.pose.pose = res->pose;
+     603        4156 :       ph.publish(msg_out);
+     604             :     } else {
+     605           6 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Could not transform pose to %s. Not republishing odom in this frame.", getPrintName().c_str(), frame_id.c_str());
+     606           6 :       return;
+     607             :     }
+     608             :   }
+     609             : 
+     610             :   /*//}*/
+     611             : };
+     612             : 
+     613             : /*//}*/
+     614             : 
+     615             : }  // namespace mrs_uav_managers
+     616             : 
+     617             : #endif
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/constraint_manager.cpp.func-sort-c.html b/mrs_uav_managers/src/constraint_manager.cpp.func-sort-c.html new file mode 100644 index 0000000000..85d4605e57 --- /dev/null +++ b/mrs_uav_managers/src/constraint_manager.cpp.func-sort-c.html @@ -0,0 +1,104 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/constraint_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - constraint_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:14822765.2 %
Date:2023-11-29 14:09:54Functions:6875.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager22callbackSetConstraintsERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE0
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager27callbackConstraintsOverrideERN8mrs_msgs27ConstraintsOverrideRequest_ISaIvEEERNS2_28ConstraintsOverrideResponse_IS4_EE0
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager14setConstraintsENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager6onInitEv7
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager16timerDiagnosticsERKN3ros10TimerEventE116
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager14stringInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS7_SaIS7_EE189
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager25timerConstraintManagementERKN3ros10TimerEventE1191
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/constraint_manager.cpp.func.html b/mrs_uav_managers/src/constraint_manager.cpp.func.html new file mode 100644 index 0000000000..ca2971526b --- /dev/null +++ b/mrs_uav_managers/src/constraint_manager.cpp.func.html @@ -0,0 +1,104 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/constraint_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - constraint_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:14822765.2 %
Date:2023-11-29 14:09:54Functions:6875.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager14setConstraintsENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager14stringInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS7_SaIS7_EE189
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager16timerDiagnosticsERKN3ros10TimerEventE116
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager22callbackSetConstraintsERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE0
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager25timerConstraintManagementERKN3ros10TimerEventE1191
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager27callbackConstraintsOverrideERN8mrs_msgs27ConstraintsOverrideRequest_ISaIvEEERNS2_28ConstraintsOverrideResponse_IS4_EE0
_ZN16mrs_uav_managers18constraint_manager17ConstraintManager6onInitEv7
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/constraint_manager.cpp.gcov.html b/mrs_uav_managers/src/constraint_manager.cpp.gcov.html new file mode 100644 index 0000000000..a62cc2ac15 --- /dev/null +++ b/mrs_uav_managers/src/constraint_manager.cpp.gcov.html @@ -0,0 +1,698 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/constraint_manager.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - constraint_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:14822765.2 %
Date:2023-11-29 14:09:54Functions:6875.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /* includes //{ */
+       2             : 
+       3             : #include <ros/ros.h>
+       4             : #include <nodelet/nodelet.h>
+       5             : 
+       6             : #include <std_msgs/String.h>
+       7             : 
+       8             : #include <mrs_msgs/ConstraintManagerDiagnostics.h>
+       9             : #include <mrs_msgs/EstimationDiagnostics.h>
+      10             : #include <mrs_msgs/DynamicsConstraintsSrv.h>
+      11             : #include <mrs_msgs/DynamicsConstraintsSrvRequest.h>
+      12             : #include <mrs_msgs/String.h>
+      13             : #include <mrs_msgs/ConstraintsOverride.h>
+      14             : 
+      15             : #include <mrs_lib/profiler.h>
+      16             : #include <mrs_lib/scope_timer.h>
+      17             : #include <mrs_lib/param_loader.h>
+      18             : #include <mrs_lib/mutex.h>
+      19             : #include <mrs_lib/publisher_handler.h>
+      20             : #include <mrs_lib/service_client_handler.h>
+      21             : #include <mrs_lib/subscribe_handler.h>
+      22             : 
+      23             : #include <dynamic_reconfigure/ReconfigureRequest.h>
+      24             : #include <dynamic_reconfigure/Reconfigure.h>
+      25             : #include <dynamic_reconfigure/Config.h>
+      26             : 
+      27             : //}
+      28             : 
+      29             : namespace mrs_uav_managers
+      30             : {
+      31             : 
+      32             : namespace constraint_manager
+      33             : {
+      34             : 
+      35             : /* //{ class ConstraintManager */
+      36             : 
+      37             : class ConstraintManager : public nodelet::Nodelet {
+      38             : 
+      39             : public:
+      40             :   virtual void onInit();
+      41             : 
+      42             : private:
+      43             :   ros::NodeHandle nh_;
+      44             :   bool            is_initialized_ = false;
+      45             : 
+      46             :   // | ----------------------- parameters ----------------------- |
+      47             : 
+      48             :   std::vector<std::string> _estimator_type_names_;
+      49             : 
+      50             :   std::vector<std::string>                                       _constraint_names_;
+      51             :   std::map<std::string, mrs_msgs::DynamicsConstraintsSrvRequest> _constraints_;
+      52             : 
+      53             :   std::map<std::string, std::vector<std::string>> _map_type_allowed_constraints_;
+      54             :   std::map<std::string, std::string>              _map_type_default_constraints_;
+      55             : 
+      56             :   // | --------------------- service clients -------------------- |
+      57             : 
+      58             :   mrs_lib::ServiceClientHandler<mrs_msgs::DynamicsConstraintsSrv> sc_set_constraints_;
+      59             : 
+      60             :   // | ----------------------- subscribers ---------------------- |
+      61             : 
+      62             :   mrs_lib::SubscribeHandler<mrs_msgs::EstimationDiagnostics> sh_estimation_diag_;
+      63             : 
+      64             :   // | ------------- constraint management ------------- |
+      65             : 
+      66             :   bool setConstraints(std::string constraints_names);
+      67             : 
+      68             :   ros::ServiceServer service_server_set_constraints_;
+      69             :   bool               callbackSetConstraints(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res);
+      70             : 
+      71             :   std::string last_estimator_name_;
+      72             :   std::mutex  mutex_last_estimator_name_;
+      73             : 
+      74             :   void       timerConstraintManagement(const ros::TimerEvent& event);
+      75             :   ros::Timer timer_constraint_management_;
+      76             :   double     _constraint_management_rate_;
+      77             : 
+      78             :   std::string current_constraints_;
+      79             :   std::mutex  mutex_current_constraints_;
+      80             : 
+      81             :   // | ------------------ constraints override ------------------ |
+      82             : 
+      83             :   ros::ServiceServer service_server_constraints_override_;
+      84             :   bool               callbackConstraintsOverride(mrs_msgs::ConstraintsOverride::Request& req, mrs_msgs::ConstraintsOverride::Response& res);
+      85             : 
+      86             :   std::atomic<bool>                    override_constraints_         = false;
+      87             :   std::atomic<bool>                    constraints_override_updated_ = false;
+      88             :   std::mutex                           mutex_constraints_override_;
+      89             :   mrs_msgs::ConstraintsOverrideRequest constraints_override_;
+      90             : 
+      91             :   // | ------------------ diagnostics publisher ----------------- |
+      92             : 
+      93             :   mrs_lib::PublisherHandler<mrs_msgs::ConstraintManagerDiagnostics> ph_diagnostics_;
+      94             : 
+      95             :   void       timerDiagnostics(const ros::TimerEvent& event);
+      96             :   ros::Timer timer_diagnostics_;
+      97             :   double     _diagnostics_rate_;
+      98             : 
+      99             :   // | ------------------------ profiler ------------------------ |
+     100             : 
+     101             :   mrs_lib::Profiler profiler_;
+     102             :   bool              _profiler_enabled_ = false;
+     103             : 
+     104             :   // | ------------------- scope timer logger ------------------- |
+     105             : 
+     106             :   bool                                       scope_timer_enabled_ = false;
+     107             :   std::shared_ptr<mrs_lib::ScopeTimerLogger> scope_timer_logger_;
+     108             : 
+     109             :   // | ------------------------- helpers ------------------------ |
+     110             : 
+     111             :   bool stringInVector(const std::string& value, const std::vector<std::string>& vector);
+     112             : };
+     113             : 
+     114             : //}
+     115             : 
+     116             : /* //{ onInit() */
+     117             : 
+     118           7 : void ConstraintManager::onInit() {
+     119             : 
+     120           7 :   nh_ = nodelet::Nodelet::getMTPrivateNodeHandle();
+     121             : 
+     122           7 :   ros::Time::waitForValid();
+     123             : 
+     124           7 :   ROS_INFO("[ConstraintManager]: initializing");
+     125             : 
+     126             :   // | ------------------------- params ------------------------- |
+     127             : 
+     128          14 :   mrs_lib::ParamLoader param_loader(nh_, "ConstraintManager");
+     129             : 
+     130          14 :   std::string custom_config_path;
+     131          14 :   std::string platform_config_path;
+     132             : 
+     133           7 :   param_loader.loadParam("custom_config", custom_config_path);
+     134           7 :   param_loader.loadParam("platform_config", platform_config_path);
+     135             : 
+     136           7 :   if (custom_config_path != "") {
+     137           7 :     param_loader.addYamlFile(custom_config_path);
+     138             :   }
+     139             : 
+     140           7 :   if (platform_config_path != "") {
+     141           7 :     param_loader.addYamlFile(platform_config_path);
+     142             :   }
+     143             : 
+     144           7 :   param_loader.addYamlFileFromParam("private_config");
+     145           7 :   param_loader.addYamlFileFromParam("public_config");
+     146           7 :   param_loader.addYamlFileFromParam("public_constraints");
+     147             : 
+     148          14 :   const std::string yaml_prefix = "mrs_uav_managers/constraint_manager/";
+     149             : 
+     150             :   // params passed from the launch file are not prefixed
+     151           7 :   param_loader.loadParam("enable_profiler", _profiler_enabled_);
+     152             : 
+     153           7 :   param_loader.loadParam(yaml_prefix + "constraints", _constraint_names_);
+     154             : 
+     155           7 :   param_loader.loadParam(yaml_prefix + "estimator_types", _estimator_type_names_);
+     156             : 
+     157           7 :   param_loader.loadParam(yaml_prefix + "rate", _constraint_management_rate_);
+     158           7 :   param_loader.loadParam(yaml_prefix + "diagnostics_rate", _diagnostics_rate_);
+     159             : 
+     160           7 :   std::vector<std::string>::iterator it;
+     161             : 
+     162             :   // loading constraint names
+     163          28 :   for (it = _constraint_names_.begin(); it != _constraint_names_.end(); ++it) {
+     164             : 
+     165          21 :     ROS_INFO_STREAM("[ConstraintManager]: loading constraints '" << *it << "'");
+     166             : 
+     167          21 :     mrs_msgs::DynamicsConstraintsSrvRequest new_constraints;
+     168             : 
+     169          21 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/speed", new_constraints.constraints.horizontal_speed);
+     170          21 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/acceleration", new_constraints.constraints.horizontal_acceleration);
+     171          21 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/jerk", new_constraints.constraints.horizontal_jerk);
+     172          21 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/snap", new_constraints.constraints.horizontal_snap);
+     173             : 
+     174          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/ascending/speed", new_constraints.constraints.vertical_ascending_speed);
+     175          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/ascending/acceleration", new_constraints.constraints.vertical_ascending_acceleration);
+     176          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/ascending/jerk", new_constraints.constraints.vertical_ascending_jerk);
+     177          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/ascending/snap", new_constraints.constraints.vertical_ascending_snap);
+     178             : 
+     179          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/descending/speed", new_constraints.constraints.vertical_descending_speed);
+     180          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/descending/acceleration", new_constraints.constraints.vertical_descending_acceleration);
+     181          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/descending/jerk", new_constraints.constraints.vertical_descending_jerk);
+     182          21 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/descending/snap", new_constraints.constraints.vertical_descending_snap);
+     183             : 
+     184          21 :     param_loader.loadParam(yaml_prefix + *it + "/heading/speed", new_constraints.constraints.heading_speed);
+     185          21 :     param_loader.loadParam(yaml_prefix + *it + "/heading/acceleration", new_constraints.constraints.heading_acceleration);
+     186          21 :     param_loader.loadParam(yaml_prefix + *it + "/heading/jerk", new_constraints.constraints.heading_jerk);
+     187          21 :     param_loader.loadParam(yaml_prefix + *it + "/heading/snap", new_constraints.constraints.heading_snap);
+     188             : 
+     189          21 :     param_loader.loadParam(yaml_prefix + *it + "/angular_speed/roll", new_constraints.constraints.roll_rate);
+     190          21 :     param_loader.loadParam(yaml_prefix + *it + "/angular_speed/pitch", new_constraints.constraints.pitch_rate);
+     191          21 :     param_loader.loadParam(yaml_prefix + *it + "/angular_speed/yaw", new_constraints.constraints.yaw_rate);
+     192             : 
+     193             :     double tilt_deg;
+     194             : 
+     195          21 :     param_loader.loadParam(yaml_prefix + *it + "/tilt", tilt_deg);
+     196             : 
+     197          21 :     new_constraints.constraints.tilt = M_PI * (tilt_deg / 180.0);
+     198             : 
+     199          21 :     _constraints_.insert(std::pair<std::string, mrs_msgs::DynamicsConstraintsSrvRequest>(*it, new_constraints));
+     200             :   }
+     201             : 
+     202             :   // loading the allowed constraints lists
+     203          56 :   for (it = _estimator_type_names_.begin(); it != _estimator_type_names_.end(); ++it) {
+     204             : 
+     205          49 :     std::vector<std::string> temp_vector;
+     206          49 :     param_loader.loadParam(yaml_prefix + "allowed_constraints/" + *it, temp_vector);
+     207             : 
+     208          49 :     std::vector<std::string>::iterator it2;
+     209         182 :     for (it2 = temp_vector.begin(); it2 != temp_vector.end(); ++it2) {
+     210         133 :       if (!stringInVector(*it2, _constraint_names_)) {
+     211           0 :         ROS_ERROR("[ConstraintManager]: the element '%s' of %s/allowed_constraints is not a valid constraint!", it2->c_str(), it->c_str());
+     212           0 :         ros::shutdown();
+     213             :       }
+     214             :     }
+     215             : 
+     216          49 :     _map_type_allowed_constraints_.insert(std::pair<std::string, std::vector<std::string>>(*it, temp_vector));
+     217             :   }
+     218             : 
+     219             :   // loading the default constraints
+     220          56 :   for (it = _estimator_type_names_.begin(); it != _estimator_type_names_.end(); ++it) {
+     221             : 
+     222          49 :     std::string temp_str;
+     223          49 :     param_loader.loadParam(yaml_prefix + "default_constraints/" + *it, temp_str);
+     224             : 
+     225          49 :     if (!stringInVector(temp_str, _map_type_allowed_constraints_.at(*it))) {
+     226           0 :       ROS_ERROR("[ConstraintManager]: the element '%s' of %s/allowed_constraints is not a valid constraint!", temp_str.c_str(), it->c_str());
+     227           0 :       ros::shutdown();
+     228             :     }
+     229             : 
+     230          49 :     _map_type_default_constraints_.insert(std::pair<std::string, std::string>(*it, temp_str));
+     231             :   }
+     232             : 
+     233           7 :   ROS_INFO("[ConstraintManager]: done loading dynamical params");
+     234             : 
+     235           7 :   current_constraints_ = "";
+     236           7 :   last_estimator_name_ = "";
+     237             : 
+     238             :   // | ------------------------ services ------------------------ |
+     239             : 
+     240           7 :   service_server_set_constraints_ = nh_.advertiseService("set_constraints_in", &ConstraintManager::callbackSetConstraints, this);
+     241             : 
+     242           7 :   service_server_constraints_override_ = nh_.advertiseService("constraints_override_in", &ConstraintManager::callbackConstraintsOverride, this);
+     243             : 
+     244           7 :   sc_set_constraints_ = mrs_lib::ServiceClientHandler<mrs_msgs::DynamicsConstraintsSrv>(nh_, "set_constraints_out");
+     245             : 
+     246             :   // | ----------------------- subscribers ---------------------- |
+     247             : 
+     248          14 :   mrs_lib::SubscribeHandlerOptions shopts;
+     249           7 :   shopts.nh                 = nh_;
+     250           7 :   shopts.node_name          = "ConstraintManager";
+     251           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+     252           7 :   shopts.threadsafe         = true;
+     253           7 :   shopts.autostart          = true;
+     254           7 :   shopts.queue_size         = 10;
+     255           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     256             : 
+     257           7 :   sh_estimation_diag_ = mrs_lib::SubscribeHandler<mrs_msgs::EstimationDiagnostics>(shopts, "estimation_diagnostics_in");
+     258             : 
+     259             :   // | ----------------------- publishers ----------------------- |
+     260             : 
+     261           7 :   ph_diagnostics_ = mrs_lib::PublisherHandler<mrs_msgs::ConstraintManagerDiagnostics>(nh_, "diagnostics_out", 1);
+     262             : 
+     263             :   // | ------------------------- timers ------------------------- |
+     264             : 
+     265           7 :   timer_constraint_management_ = nh_.createTimer(ros::Rate(_constraint_management_rate_), &ConstraintManager::timerConstraintManagement, this);
+     266           7 :   timer_diagnostics_           = nh_.createTimer(ros::Rate(_diagnostics_rate_), &ConstraintManager::timerDiagnostics, this);
+     267             : 
+     268             :   // | ------------------------ profiler ------------------------ |
+     269             : 
+     270           7 :   profiler_ = mrs_lib::Profiler(nh_, "ConstraintManager", _profiler_enabled_);
+     271             : 
+     272             :   // | ------------------- scope timer logger ------------------- |
+     273             : 
+     274           7 :   param_loader.loadParam(yaml_prefix + "scope_timer/enabled", scope_timer_enabled_);
+     275          21 :   const std::string scope_timer_log_filename = param_loader.loadParam2("scope_timer/log_filename", std::string(""));
+     276           7 :   scope_timer_logger_                        = std::make_shared<mrs_lib::ScopeTimerLogger>(scope_timer_log_filename, scope_timer_enabled_);
+     277             : 
+     278             :   // | ----------------------- finish init ---------------------- |
+     279             : 
+     280           7 :   if (!param_loader.loadedSuccessfully()) {
+     281           0 :     ROS_ERROR("[ConstraintManager]: Could not load all parameters!");
+     282           0 :     ros::shutdown();
+     283             :   }
+     284             : 
+     285           7 :   is_initialized_ = true;
+     286             : 
+     287           7 :   ROS_INFO("[ConstraintManager]: initialized");
+     288             : 
+     289           7 :   ROS_DEBUG("[ConstraintManager]: debug output is enabled");
+     290           7 : }
+     291             : 
+     292             : //}
+     293             : 
+     294             : // --------------------------------------------------------------
+     295             : // |                           methods                          |
+     296             : // --------------------------------------------------------------
+     297             : 
+     298             : /* setConstraints() //{ */
+     299             : 
+     300           7 : bool ConstraintManager::setConstraints(std::string constraints_name) {
+     301             : 
+     302           7 :   std::map<std::string, mrs_msgs::DynamicsConstraintsSrvRequest>::iterator it;
+     303           7 :   it = _constraints_.find(constraints_name);
+     304             : 
+     305           7 :   if (it == _constraints_.end()) {
+     306           0 :     ROS_ERROR("[ConstraintManager]: could not setConstraints(), the constraint name '%s' is not on the list", constraints_name.c_str());
+     307           0 :     return false;
+     308             :   }
+     309             : 
+     310          14 :   mrs_msgs::DynamicsConstraintsSrv srv_call;
+     311             : 
+     312           7 :   srv_call.request = it->second;
+     313             : 
+     314           7 :   if (override_constraints_) {
+     315             : 
+     316           0 :     auto constraints_override = mrs_lib::get_mutexed(mutex_constraints_override_, constraints_override_);
+     317             : 
+     318           0 :     if (constraints_override.acceleration_horizontal > 0 &&
+     319           0 :         constraints_override.acceleration_horizontal <= srv_call.request.constraints.horizontal_acceleration) {
+     320           0 :       srv_call.request.constraints.horizontal_acceleration = constraints_override.acceleration_horizontal;
+     321             :     } else {
+     322           0 :       ROS_ERROR_THROTTLE(1.0, "[ConstraintManager]: required horizontal acceleration override is out of bounds");
+     323             :     }
+     324             : 
+     325           0 :     if (constraints_override.acceleration_vertical > 0 &&
+     326           0 :         constraints_override.acceleration_vertical <= srv_call.request.constraints.vertical_ascending_acceleration &&
+     327           0 :         constraints_override.acceleration_vertical <= srv_call.request.constraints.vertical_descending_acceleration) {
+     328           0 :       srv_call.request.constraints.vertical_ascending_acceleration  = constraints_override.acceleration_vertical;
+     329           0 :       srv_call.request.constraints.vertical_descending_acceleration = constraints_override.acceleration_vertical;
+     330             :     } else {
+     331           0 :       ROS_ERROR_THROTTLE(1.0, "[ConstraintManager]: required vertical acceleration override is out of bounds");
+     332             :     }
+     333             :   }
+     334             : 
+     335           7 :   bool res = sc_set_constraints_.call(srv_call);
+     336             : 
+     337           7 :   if (!res) {
+     338             : 
+     339           0 :     ROS_WARN_THROTTLE(1.0, "[ConstraintManager]: the service for setting constraints has failed!");
+     340           0 :     return false;
+     341             : 
+     342             :   } else {
+     343             : 
+     344           7 :     if (srv_call.response.success) {
+     345             : 
+     346           7 :       mrs_lib::set_mutexed(mutex_current_constraints_, constraints_name, current_constraints_);
+     347           7 :       return true;
+     348             : 
+     349             :     } else {
+     350             : 
+     351           0 :       ROS_WARN_THROTTLE(1.0, "[ConstraintManager]: set service for setting constraints returned: '%s'", srv_call.response.message.c_str());
+     352           0 :       return false;
+     353             :     }
+     354             :   }
+     355             : }
+     356             : 
+     357             : //}
+     358             : 
+     359             : // --------------------------------------------------------------
+     360             : // |                          callbacks                         |
+     361             : // --------------------------------------------------------------
+     362             : 
+     363             : // | -------------------- service callbacks ------------------- |
+     364             : 
+     365             : /* //{ callbackSetConstraints() */
+     366             : 
+     367           0 : bool ConstraintManager::callbackSetConstraints(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res) {
+     368             : 
+     369           0 :   if (!is_initialized_) {
+     370           0 :     return false;
+     371             :   }
+     372             : 
+     373           0 :   std::stringstream ss;
+     374             : 
+     375           0 :   if (!sh_estimation_diag_.hasMsg()) {
+     376             : 
+     377           0 :     ss << "missing odometry diagnostics";
+     378             : 
+     379           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ConstraintManager]: " << ss.str());
+     380             : 
+     381           0 :     res.message = ss.str();
+     382           0 :     res.success = false;
+     383           0 :     return true;
+     384             :   }
+     385             : 
+     386           0 :   auto estimation_diagnostics = *sh_estimation_diag_.getMsg();
+     387             : 
+     388           0 :   if (!stringInVector(req.value, _constraint_names_)) {
+     389             : 
+     390           0 :     ss << "the constraints '" << req.value.c_str() << "' do not exist (in the ConstraintManager's config)";
+     391             : 
+     392           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ConstraintManager]: " << ss.str());
+     393             : 
+     394           0 :     res.message = ss.str();
+     395           0 :     res.success = false;
+     396           0 :     return true;
+     397             :   }
+     398             : 
+     399           0 :   if (!stringInVector(req.value, _map_type_allowed_constraints_.at(estimation_diagnostics.current_state_estimator))) {
+     400             : 
+     401           0 :     ss << "the constraints '" << req.value.c_str() << "' are not allowed given the current odometry type";
+     402             : 
+     403           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ConstraintManager]: " << ss.str());
+     404             : 
+     405           0 :     res.message = ss.str();
+     406           0 :     res.success = false;
+     407           0 :     return true;
+     408             :   }
+     409             : 
+     410           0 :   override_constraints_ = false;
+     411             : 
+     412             :   // try to set the constraints
+     413           0 :   if (!setConstraints(req.value)) {
+     414             : 
+     415           0 :     ss << "the ControlManager could not set the constraints";
+     416             : 
+     417           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ConstraintManager]: " << ss.str());
+     418             : 
+     419           0 :     res.message = ss.str();
+     420           0 :     res.success = false;
+     421           0 :     return true;
+     422             : 
+     423             :   } else {
+     424             : 
+     425           0 :     ss << "the constraints '" << req.value.c_str() << "' were set";
+     426             : 
+     427           0 :     ROS_INFO_STREAM_THROTTLE(1.0, "[ConstraintManager]: " << ss.str());
+     428             : 
+     429           0 :     res.message = ss.str();
+     430           0 :     res.success = true;
+     431           0 :     return true;
+     432             :   }
+     433             : }
+     434             : 
+     435             : //}
+     436             : 
+     437             : /* callackConstraintsOverride() //{ */
+     438             : 
+     439           0 : bool ConstraintManager::callbackConstraintsOverride(mrs_msgs::ConstraintsOverride::Request& req, mrs_msgs::ConstraintsOverride::Response& res) {
+     440             : 
+     441           0 :   if (!is_initialized_) {
+     442           0 :     return false;
+     443             :   }
+     444             : 
+     445             :   {
+     446           0 :     std::scoped_lock lock(mutex_constraints_override_);
+     447             : 
+     448           0 :     constraints_override_ = req;
+     449             :   }
+     450             : 
+     451           0 :   override_constraints_         = true;
+     452           0 :   constraints_override_updated_ = true;
+     453             : 
+     454           0 :   ROS_INFO_THROTTLE(0.1, "[ConstraintManager]: setting constraints override");
+     455             : 
+     456           0 :   res.message = "override set";
+     457           0 :   res.success = true;
+     458             : 
+     459           0 :   return true;
+     460             : }
+     461             : 
+     462             : //}
+     463             : 
+     464             : // --------------------------------------------------------------
+     465             : // |                           timers                           |
+     466             : // --------------------------------------------------------------
+     467             : 
+     468             : /* timerConstraintManagement() //{ */
+     469             : 
+     470        1191 : void ConstraintManager::timerConstraintManagement(const ros::TimerEvent& event) {
+     471             : 
+     472        1191 :   if (!is_initialized_) {
+     473         297 :     return;
+     474             :   }
+     475             : 
+     476        2382 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerConstraintManagement", _constraint_management_rate_, 0.01, event);
+     477        2382 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ContraintManager::timerConstraintManagement", scope_timer_logger_, scope_timer_enabled_);
+     478             : 
+     479        1191 :   auto current_constraints = mrs_lib::get_mutexed(mutex_current_constraints_, current_constraints_);
+     480        1191 :   auto last_estimator_name = mrs_lib::get_mutexed(mutex_last_estimator_name_, last_estimator_name_);
+     481             : 
+     482        1191 :   if (!sh_estimation_diag_.hasMsg()) {
+     483         297 :     return;
+     484             :   }
+     485             : 
+     486         894 :   auto estimation_diagnostics = *sh_estimation_diag_.getMsg();
+     487             : 
+     488             :   // | --- automatically set constraints when the state estimator changes -- |
+     489         894 :   if (estimation_diagnostics.current_state_estimator != last_estimator_name_) {
+     490             : 
+     491           7 :     ROS_INFO_THROTTLE(1.0, "[ConstraintManager]: the state estimator has changed! %s -> %s", last_estimator_name_.c_str(),
+     492             :                       estimation_diagnostics.current_state_estimator.c_str());
+     493             : 
+     494           7 :     std::map<std::string, std::string>::iterator it;
+     495           7 :     it = _map_type_default_constraints_.find(estimation_diagnostics.current_state_estimator);
+     496             : 
+     497           7 :     if (it == _map_type_default_constraints_.end()) {
+     498             : 
+     499           0 :       ROS_WARN_THROTTLE(1.0, "[ConstraintManager]: the state estimator type '%s' was not specified in the constraint_manager's config!",
+     500             :                         estimation_diagnostics.current_state_estimator.c_str());
+     501             : 
+     502             :     } else {
+     503             : 
+     504             :       // if the current constraints are within the allowed state estimator types, do nothing
+     505           7 :       if (stringInVector(current_constraints, _map_type_allowed_constraints_.at(estimation_diagnostics.current_state_estimator))) {
+     506             : 
+     507           0 :         last_estimator_name = estimation_diagnostics.current_state_estimator;
+     508             : 
+     509             :         // else, try to set the initial constraints
+     510             :       } else {
+     511             : 
+     512           7 :         ROS_WARN_THROTTLE(1.0, "[ConstraintManager]: the current constraints '%s' are not within the allowed constraints for '%s'", current_constraints.c_str(),
+     513             :                           estimation_diagnostics.current_state_estimator.c_str());
+     514             : 
+     515           7 :         if (setConstraints(it->second)) {
+     516             : 
+     517           7 :           last_estimator_name = estimation_diagnostics.current_state_estimator;
+     518             : 
+     519           7 :           ROS_INFO_THROTTLE(1.0, "[ConstraintManager]: constraints set to initial: '%s'", it->second.c_str());
+     520             : 
+     521             :         } else {
+     522             : 
+     523           0 :           ROS_WARN_THROTTLE(1.0, "[ConstraintManager]: could not set constraints!");
+     524             :         }
+     525             :       }
+     526             :     }
+     527             :   }
+     528             : 
+     529         894 :   if (constraints_override_updated_) {
+     530             : 
+     531           0 :     std::map<std::string, std::string>::iterator it;
+     532           0 :     it = _map_type_default_constraints_.find(last_estimator_name_);
+     533             : 
+     534           0 :     ROS_INFO_THROTTLE(0.1, "[ConstraintManager]: re-setting constraints with user value override");
+     535             : 
+     536           0 :     if (setConstraints(it->second)) {
+     537           0 :       constraints_override_updated_ = false;
+     538             :     } else {
+     539           0 :       ROS_WARN_THROTTLE(1.0, "[ConstraintManager]: could not re-set the constraints!");
+     540             :     }
+     541             :   }
+     542             : 
+     543         894 :   mrs_lib::set_mutexed(mutex_last_estimator_name_, last_estimator_name, last_estimator_name_);
+     544             : }
+     545             : 
+     546             : //}
+     547             : 
+     548             : /* timerDiagnostics() //{ */
+     549             : 
+     550         116 : void ConstraintManager::timerDiagnostics(const ros::TimerEvent& event) {
+     551             : 
+     552         116 :   if (!is_initialized_) {
+     553          29 :     return;
+     554             :   }
+     555             : 
+     556         232 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerDiagnostics", _diagnostics_rate_, 0.01, event);
+     557         232 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ContraintManager::timerDiagnostics", scope_timer_logger_, scope_timer_enabled_);
+     558             : 
+     559         116 :   if (!sh_estimation_diag_.hasMsg()) {
+     560          29 :     ROS_WARN_THROTTLE(10.0, "[ConstraintManager]: can not do constraint management, missing estimation diagnostics!");
+     561          29 :     return;
+     562             :   }
+     563             : 
+     564         174 :   auto estimation_diagnostics = *sh_estimation_diag_.getMsg();
+     565             : 
+     566         174 :   auto current_constraints = mrs_lib::get_mutexed(mutex_current_constraints_, current_constraints_);
+     567             : 
+     568         174 :   mrs_msgs::ConstraintManagerDiagnostics diagnostics;
+     569             : 
+     570          87 :   diagnostics.stamp        = ros::Time::now();
+     571          87 :   diagnostics.current_name = current_constraints;
+     572          87 :   diagnostics.loaded       = _constraint_names_;
+     573             : 
+     574             :   // get the available constraints
+     575             :   {
+     576          87 :     std::map<std::string, std::vector<std::string>>::iterator it;
+     577          87 :     it = _map_type_allowed_constraints_.find(estimation_diagnostics.current_state_estimator);
+     578             : 
+     579          87 :     if (it == _map_type_allowed_constraints_.end()) {
+     580           0 :       ROS_WARN_THROTTLE(1.0, "[ConstraintManager]: the odometry.type '%s' was not specified in the constraint_manager's config!",
+     581             :                         estimation_diagnostics.current_state_estimator.c_str());
+     582             :     } else {
+     583          87 :       diagnostics.available = it->second;
+     584             :     }
+     585             :   }
+     586             : 
+     587             :   // get the current constraint values
+     588             :   {
+     589          87 :     std::map<std::string, mrs_msgs::DynamicsConstraintsSrvRequest>::iterator it;
+     590          87 :     it = _constraints_.find(current_constraints);
+     591             : 
+     592          87 :     diagnostics.current_values = it->second.constraints;
+     593             :   }
+     594             : 
+     595          87 :   ph_diagnostics_.publish(diagnostics);
+     596             : }
+     597             : 
+     598             : //}
+     599             : 
+     600             : // --------------------------------------------------------------
+     601             : // |                          routines                          |
+     602             : // --------------------------------------------------------------
+     603             : 
+     604             : /* stringInVector() //{ */
+     605             : 
+     606         189 : bool ConstraintManager::stringInVector(const std::string& value, const std::vector<std::string>& vector) {
+     607             : 
+     608         189 :   if (std::find(vector.begin(), vector.end(), value) == vector.end()) {
+     609           7 :     return false;
+     610             :   } else {
+     611         182 :     return true;
+     612             :   }
+     613             : }
+     614             : 
+     615             : //}
+     616             : 
+     617             : }  // namespace constraint_manager
+     618             : 
+     619             : }  // namespace mrs_uav_managers
+     620             : 
+     621             : #include <pluginlib/class_list_macros.h>
+     622           7 : PLUGINLIB_EXPORT_CLASS(mrs_uav_managers::constraint_manager::ConstraintManager, nodelet::Nodelet)
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/common/common.cpp.func-sort-c.html b/mrs_uav_managers/src/control_manager/common/common.cpp.func-sort-c.html new file mode 100644 index 0000000000..ea8f6483b2 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/common/common.cpp.func-sort-c.html @@ -0,0 +1,196 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/common/common.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager/common - common.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:15756327.9 %
Date:2023-11-29 14:09:54Functions:123138.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager15getHighestOuputERKNS0_25ControlOutputModalities_tE0
_ZN16mrs_uav_managers15control_manager16RCChannelToRangeEddd0
_ZN16mrs_uav_managers15control_manager16validateOdometryERKN8nav_msgs9Odometry_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKdS7_0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNS1_9UavState_IS3_EERKd0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKd0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager24validateHwApiActuatorCmdERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager24validateHwApiPositionCmdERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager25validateVelocityReferenceERKN8mrs_msgs18VelocityReference_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager27validateHwApiVelocityHdgCmdERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager28validateHwApiControlGroupCmdERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager31validateHwApiAccelerationHdgCmdERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager31validateHwApiVelocityHdgRateCmdERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager35validateHwApiAccelerationHdgRateCmdERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager26loadDetailedUavModelParamsERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_SB_7
_ZN16mrs_uav_managers15control_manager11idxInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS6_SaIS6_EE124
_ZN16mrs_uav_managers15control_manager17validateReferenceERKN8mrs_msgs10Reference_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_437
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKd438
_ZN16mrs_uav_managers15control_manager23initializeDefaultOutputERKNS0_25ControlOutputModalities_tERKN8mrs_msgs9UavState_ISaIvEEERKdSB_438
_ZN16mrs_uav_managers15control_manager14getLowestOuputERKNS0_25ControlOutputModalities_tE473
_ZN16mrs_uav_managers15control_manager28validateHwApiAttitudeRateCmdERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_5428
_ZN16mrs_uav_managers15control_manager22validateTrackerCommandERKSt8optionalIN8mrs_msgs15TrackerCommand_ISaIvEEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESG_5465
_ZN16mrs_uav_managers15control_manager21validateControlOutputERKNS_10Controller13ControlOutputERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_6863
_ZN16mrs_uav_managers15control_manager16validateUavStateERKN8mrs_msgs9UavState_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_8286
_ZN16mrs_uav_managers15control_manager24validateHwApiAttitudeCmdERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_8297
_ZN16mrs_uav_managers15control_manager15extractThrottleERKNS_10Controller13ControlOutputE9635
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/common/common.cpp.func.html b/mrs_uav_managers/src/control_manager/common/common.cpp.func.html new file mode 100644 index 0000000000..a392e8afc4 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/common/common.cpp.func.html @@ -0,0 +1,196 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/common/common.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager/common - common.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:15756327.9 %
Date:2023-11-29 14:09:54Functions:123138.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager11idxInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS6_SaIS6_EE124
_ZN16mrs_uav_managers15control_manager14getLowestOuputERKNS0_25ControlOutputModalities_tE473
_ZN16mrs_uav_managers15control_manager15extractThrottleERKNS_10Controller13ControlOutputE9635
_ZN16mrs_uav_managers15control_manager15getHighestOuputERKNS0_25ControlOutputModalities_tE0
_ZN16mrs_uav_managers15control_manager16RCChannelToRangeEddd0
_ZN16mrs_uav_managers15control_manager16validateOdometryERKN8nav_msgs9Odometry_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager16validateUavStateERKN8mrs_msgs9UavState_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_8286
_ZN16mrs_uav_managers15control_manager17validateReferenceERKN8mrs_msgs10Reference_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_437
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKdS7_0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNS1_9UavState_IS3_EERKd0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKd438
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKd0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager18initializeHwApiCmdERN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNS1_9UavState_IS3_EE0
_ZN16mrs_uav_managers15control_manager21validateControlOutputERKNS_10Controller13ControlOutputERKNS0_25ControlOutputModalities_tERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESF_6863
_ZN16mrs_uav_managers15control_manager22validateTrackerCommandERKSt8optionalIN8mrs_msgs15TrackerCommand_ISaIvEEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESG_5465
_ZN16mrs_uav_managers15control_manager23initializeDefaultOutputERKNS0_25ControlOutputModalities_tERKN8mrs_msgs9UavState_ISaIvEEERKdSB_438
_ZN16mrs_uav_managers15control_manager24validateHwApiActuatorCmdERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager24validateHwApiAttitudeCmdERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_8297
_ZN16mrs_uav_managers15control_manager24validateHwApiPositionCmdERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager25validateVelocityReferenceERKN8mrs_msgs18VelocityReference_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager26loadDetailedUavModelParamsERN3ros10NodeHandleERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_SB_7
_ZN16mrs_uav_managers15control_manager27validateHwApiVelocityHdgCmdERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager28validateHwApiAttitudeRateCmdERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_5428
_ZN16mrs_uav_managers15control_manager28validateHwApiControlGroupCmdERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager31validateHwApiAccelerationHdgCmdERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager31validateHwApiVelocityHdgRateCmdERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
_ZN16mrs_uav_managers15control_manager35validateHwApiAccelerationHdgRateCmdERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESE_0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/common/common.cpp.gcov.html b/mrs_uav_managers/src/control_manager/common/common.cpp.gcov.html new file mode 100644 index 0000000000..24824bf723 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/common/common.cpp.gcov.html @@ -0,0 +1,1293 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/common/common.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager/common - common.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:15756327.9 %
Date:2023-11-29 14:09:54Functions:123138.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_uav_managers/control_manager/common.h>
+       2             : 
+       3             : namespace mrs_uav_managers
+       4             : {
+       5             : 
+       6             : namespace control_manager
+       7             : {
+       8             : 
+       9             : /* idxInVector() //{ */
+      10             : 
+      11         124 : std::optional<unsigned int> idxInVector(const std::string& str, const std::vector<std::string>& vec) {
+      12             : 
+      13         354 :   for (unsigned int i = 0; i < vec.size(); i++) {
+      14         354 :     if (str == vec[i]) {
+      15         124 :       return {i};
+      16             :     }
+      17             :   }
+      18             : 
+      19           0 :   return {};
+      20             : }
+      21             : 
+      22             : //}
+      23             : 
+      24             : /* validateTrackerCommand() //{ */
+      25             : 
+      26        5465 : bool validateTrackerCommand(const std::optional<mrs_msgs::TrackerCommand>& msg, const std::string& node_name, const std::string& var_name) {
+      27             : 
+      28        5465 :   if (!msg) {
+      29           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: the optional variable '%s' is not set!!!", node_name.c_str(), var_name.c_str());
+      30           0 :     return false;
+      31             :   }
+      32             : 
+      33             :   // check positions
+      34             : 
+      35        5465 :   if (!std::isfinite(msg->position.x)) {
+      36           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->position.x'!!!", node_name.c_str(), var_name.c_str());
+      37           0 :     return false;
+      38             :   }
+      39             : 
+      40        5465 :   if (!std::isfinite(msg->position.y)) {
+      41           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->position.y'!!!", node_name.c_str(), var_name.c_str());
+      42           0 :     return false;
+      43             :   }
+      44             : 
+      45        5465 :   if (!std::isfinite(msg->position.z)) {
+      46           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->position.z'!!!", node_name.c_str(), var_name.c_str());
+      47           0 :     return false;
+      48             :   }
+      49             : 
+      50             :   // check velocities
+      51             : 
+      52        5465 :   if (!std::isfinite(msg->velocity.x)) {
+      53           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->velocity.x'!!!", node_name.c_str(), var_name.c_str());
+      54           0 :     return false;
+      55             :   }
+      56             : 
+      57        5465 :   if (!std::isfinite(msg->velocity.y)) {
+      58           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->velocity.y'!!!", node_name.c_str(), var_name.c_str());
+      59           0 :     return false;
+      60             :   }
+      61             : 
+      62        5465 :   if (!std::isfinite(msg->velocity.z)) {
+      63           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->velocity.z'!!!", node_name.c_str(), var_name.c_str());
+      64           0 :     return false;
+      65             :   }
+      66             : 
+      67             :   // check accelerations
+      68             : 
+      69        5465 :   if (!std::isfinite(msg->acceleration.x)) {
+      70           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->acceleration.x'!!!", node_name.c_str(), var_name.c_str());
+      71           0 :     return false;
+      72             :   }
+      73             : 
+      74        5465 :   if (!std::isfinite(msg->acceleration.y)) {
+      75           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->acceleration.y'!!!", node_name.c_str(), var_name.c_str());
+      76           0 :     return false;
+      77             :   }
+      78             : 
+      79        5465 :   if (!std::isfinite(msg->acceleration.z)) {
+      80           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->acceleration.z'!!!", node_name.c_str(), var_name.c_str());
+      81           0 :     return false;
+      82             :   }
+      83             : 
+      84             :   // check jerk
+      85             : 
+      86        5465 :   if (!std::isfinite(msg->jerk.x)) {
+      87           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->jerk.x'!!!", node_name.c_str(), var_name.c_str());
+      88           0 :     return false;
+      89             :   }
+      90             : 
+      91        5465 :   if (!std::isfinite(msg->jerk.y)) {
+      92           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->jerk.y'!!!", node_name.c_str(), var_name.c_str());
+      93           0 :     return false;
+      94             :   }
+      95             : 
+      96        5465 :   if (!std::isfinite(msg->jerk.z)) {
+      97           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->jerk.z'!!!", node_name.c_str(), var_name.c_str());
+      98           0 :     return false;
+      99             :   }
+     100             : 
+     101             :   // check snap
+     102             : 
+     103        5465 :   if (!std::isfinite(msg->snap.x)) {
+     104           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->snap.x'!!!", node_name.c_str(), var_name.c_str());
+     105           0 :     return false;
+     106             :   }
+     107             : 
+     108        5465 :   if (!std::isfinite(msg->snap.y)) {
+     109           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->snap.y'!!!", node_name.c_str(), var_name.c_str());
+     110           0 :     return false;
+     111             :   }
+     112             : 
+     113        5465 :   if (!std::isfinite(msg->snap.z)) {
+     114           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->snap.z'!!!", node_name.c_str(), var_name.c_str());
+     115           0 :     return false;
+     116             :   }
+     117             : 
+     118             :   // check attitude rate
+     119             : 
+     120        5465 :   if (!std::isfinite(msg->attitude_rate.x)) {
+     121           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->attitude_rate.x'!!!", node_name.c_str(), var_name.c_str());
+     122           0 :     return false;
+     123             :   }
+     124             : 
+     125        5465 :   if (!std::isfinite(msg->attitude_rate.y)) {
+     126           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->attitude_rate.y'!!!", node_name.c_str(), var_name.c_str());
+     127           0 :     return false;
+     128             :   }
+     129             : 
+     130        5465 :   if (!std::isfinite(msg->attitude_rate.z)) {
+     131           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->attitude_rate.z'!!!", node_name.c_str(), var_name.c_str());
+     132           0 :     return false;
+     133             :   }
+     134             : 
+     135             :   // check heading
+     136             : 
+     137        5465 :   if (!std::isfinite(msg->heading)) {
+     138           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->heading'!!!", node_name.c_str(), var_name.c_str());
+     139           0 :     return false;
+     140             :   }
+     141             : 
+     142        5465 :   if (!std::isfinite(msg->heading_rate)) {
+     143           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->heading_rate'!!!", node_name.c_str(), var_name.c_str());
+     144           0 :     return false;
+     145             :   }
+     146             : 
+     147        5465 :   if (!std::isfinite(msg->heading_acceleration)) {
+     148           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->heading_acceleration'!!!", node_name.c_str(), var_name.c_str());
+     149           0 :     return false;
+     150             :   }
+     151             : 
+     152        5465 :   if (!std::isfinite(msg->heading_jerk)) {
+     153           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->heading_jerk'!!!", node_name.c_str(), var_name.c_str());
+     154           0 :     return false;
+     155             :   }
+     156             : 
+     157             :   // check throttle
+     158             : 
+     159        5465 :   if (!std::isfinite(msg->throttle)) {
+     160           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s->throttle'!!!", node_name.c_str(), var_name.c_str());
+     161           0 :     return false;
+     162             :   }
+     163             : 
+     164        5465 :   return true;
+     165             : }
+     166             : 
+     167             : //}
+     168             : 
+     169             : /* validateOdometry() //{ */
+     170             : 
+     171           0 : bool validateOdometry(const nav_msgs::Odometry& msg, const std::string& node_name, const std::string& var_name) {
+     172             : 
+     173             :   // check position
+     174             : 
+     175           0 :   if (!std::isfinite(msg.pose.pose.position.x)) {
+     176           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.pose.position.x'!!!", node_name.c_str(), var_name.c_str());
+     177           0 :     return false;
+     178             :   }
+     179             : 
+     180           0 :   if (!std::isfinite(msg.pose.pose.position.y)) {
+     181           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.pose.position.y'!!!", node_name.c_str(), var_name.c_str());
+     182           0 :     return false;
+     183             :   }
+     184             : 
+     185           0 :   if (!std::isfinite(msg.pose.pose.position.z)) {
+     186           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.pose.position.z'!!!", node_name.c_str(), var_name.c_str());
+     187           0 :     return false;
+     188             :   }
+     189             : 
+     190             :   // check orientation
+     191             : 
+     192           0 :   if (!std::isfinite(msg.pose.pose.orientation.x)) {
+     193           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.pose.orientation.x'!!!", node_name.c_str(), var_name.c_str());
+     194           0 :     return false;
+     195             :   }
+     196             : 
+     197           0 :   if (!std::isfinite(msg.pose.pose.orientation.y)) {
+     198           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.pose.orientation.y'!!!", node_name.c_str(), var_name.c_str());
+     199           0 :     return false;
+     200             :   }
+     201             : 
+     202           0 :   if (!std::isfinite(msg.pose.pose.orientation.z)) {
+     203           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.pose.orientation.z'!!!", node_name.c_str(), var_name.c_str());
+     204           0 :     return false;
+     205             :   }
+     206             : 
+     207           0 :   if (!std::isfinite(msg.pose.pose.orientation.w)) {
+     208           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.pose.orientation.w'!!!", node_name.c_str(), var_name.c_str());
+     209           0 :     return false;
+     210             :   }
+     211             : 
+     212             :   // check velocity
+     213             : 
+     214           0 :   if (!std::isfinite(msg.twist.twist.linear.x)) {
+     215           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.twist.twist.linear.x'!!!", node_name.c_str(), var_name.c_str());
+     216           0 :     return false;
+     217             :   }
+     218             : 
+     219           0 :   if (!std::isfinite(msg.twist.twist.linear.y)) {
+     220           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.twist.twist.linear.y'!!!", node_name.c_str(), var_name.c_str());
+     221           0 :     return false;
+     222             :   }
+     223             : 
+     224           0 :   if (!std::isfinite(msg.twist.twist.linear.z)) {
+     225           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.twist.twist.linear.z'!!!", node_name.c_str(), var_name.c_str());
+     226           0 :     return false;
+     227             :   }
+     228             : 
+     229           0 :   return true;
+     230             : }
+     231             : 
+     232             : //}
+     233             : 
+     234             : /* validateVelocityReference() //{ */
+     235             : 
+     236           0 : bool validateVelocityReference(const mrs_msgs::VelocityReference& msg, const std::string& node_name, const std::string& var_name) {
+     237             : 
+     238             :   // check velocity
+     239             : 
+     240           0 :   if (!std::isfinite(msg.velocity.x)) {
+     241           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.x'!!!", node_name.c_str(), var_name.c_str());
+     242           0 :     return false;
+     243             :   }
+     244             : 
+     245           0 :   if (!std::isfinite(msg.velocity.y)) {
+     246           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.y'!!!", node_name.c_str(), var_name.c_str());
+     247           0 :     return false;
+     248             :   }
+     249             : 
+     250           0 :   if (!std::isfinite(msg.velocity.z)) {
+     251           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.z'!!!", node_name.c_str(), var_name.c_str());
+     252           0 :     return false;
+     253             :   }
+     254             : 
+     255           0 :   if (!std::isfinite(msg.altitude)) {
+     256           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.altitude'!!!", node_name.c_str(), var_name.c_str());
+     257           0 :     return false;
+     258             :   }
+     259             : 
+     260           0 :   if (!std::isfinite(msg.heading)) {
+     261           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading'!!!", node_name.c_str(), var_name.c_str());
+     262           0 :     return false;
+     263             :   }
+     264             : 
+     265           0 :   if (!std::isfinite(msg.heading_rate)) {
+     266           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading_rate'!!!", node_name.c_str(), var_name.c_str());
+     267           0 :     return false;
+     268             :   }
+     269             : 
+     270           0 :   return true;
+     271             : }
+     272             : 
+     273             : //}
+     274             : 
+     275             : /* validateReference() //{ */
+     276             : 
+     277         437 : bool validateReference(const mrs_msgs::Reference& msg, const std::string& node_name, const std::string& var_name) {
+     278             : 
+     279             :   // check position
+     280             : 
+     281         437 :   if (!std::isfinite(msg.position.x)) {
+     282           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.position.x'!!!", node_name.c_str(), var_name.c_str());
+     283           0 :     return false;
+     284             :   }
+     285             : 
+     286         437 :   if (!std::isfinite(msg.position.y)) {
+     287           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.position.y'!!!", node_name.c_str(), var_name.c_str());
+     288           0 :     return false;
+     289             :   }
+     290             : 
+     291         437 :   if (!std::isfinite(msg.position.z)) {
+     292           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.position.z'!!!", node_name.c_str(), var_name.c_str());
+     293           0 :     return false;
+     294             :   }
+     295             : 
+     296             :   // check heading
+     297             : 
+     298         437 :   if (!std::isfinite(msg.heading)) {
+     299           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading'!!!", node_name.c_str(), var_name.c_str());
+     300           0 :     return false;
+     301             :   }
+     302             : 
+     303         437 :   return true;
+     304             : }
+     305             : 
+     306             : //}
+     307             : 
+     308             : /* validateUavState() //{ */
+     309             : 
+     310        8286 : bool validateUavState(const mrs_msgs::UavState& msg, const std::string& node_name, const std::string& var_name) {
+     311             : 
+     312             :   // check position
+     313             : 
+     314        8286 :   if (!std::isfinite(msg.pose.position.x)) {
+     315           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.position.x'!!!", node_name.c_str(), var_name.c_str());
+     316           0 :     return false;
+     317             :   }
+     318             : 
+     319        8286 :   if (!std::isfinite(msg.pose.position.y)) {
+     320           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.position.y'!!!", node_name.c_str(), var_name.c_str());
+     321           0 :     return false;
+     322             :   }
+     323             : 
+     324        8286 :   if (!std::isfinite(msg.pose.position.z)) {
+     325           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.position.z'!!!", node_name.c_str(), var_name.c_str());
+     326           0 :     return false;
+     327             :   }
+     328             : 
+     329             :   // check orientation
+     330             : 
+     331        8286 :   if (!std::isfinite(msg.pose.orientation.x)) {
+     332           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.orientation.x'!!!", node_name.c_str(), var_name.c_str());
+     333           0 :     return false;
+     334             :   }
+     335             : 
+     336        8286 :   if (!std::isfinite(msg.pose.orientation.y)) {
+     337           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.orientation.y'!!!", node_name.c_str(), var_name.c_str());
+     338           0 :     return false;
+     339             :   }
+     340             : 
+     341        8286 :   if (!std::isfinite(msg.pose.orientation.z)) {
+     342           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.orientation.z'!!!", node_name.c_str(), var_name.c_str());
+     343           0 :     return false;
+     344             :   }
+     345             : 
+     346        8286 :   if (!std::isfinite(msg.pose.orientation.w)) {
+     347           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pose.orientation.w'!!!", node_name.c_str(), var_name.c_str());
+     348           0 :     return false;
+     349             :   }
+     350             : 
+     351             :   // check linear velocity
+     352             : 
+     353        8286 :   if (!std::isfinite(msg.velocity.linear.x)) {
+     354           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.linear.x'!!!", node_name.c_str(), var_name.c_str());
+     355           0 :     return false;
+     356             :   }
+     357             : 
+     358        8286 :   if (!std::isfinite(msg.velocity.linear.y)) {
+     359           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.linear.y'!!!", node_name.c_str(), var_name.c_str());
+     360           0 :     return false;
+     361             :   }
+     362             : 
+     363        8286 :   if (!std::isfinite(msg.velocity.linear.z)) {
+     364           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.linear.z'!!!", node_name.c_str(), var_name.c_str());
+     365           0 :     return false;
+     366             :   }
+     367             : 
+     368             :   // check angular velocity
+     369             : 
+     370        8286 :   if (!std::isfinite(msg.velocity.angular.x)) {
+     371           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.angular.x'!!!", node_name.c_str(), var_name.c_str());
+     372           0 :     return false;
+     373             :   }
+     374             : 
+     375        8286 :   if (!std::isfinite(msg.velocity.angular.y)) {
+     376           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.angular.y'!!!", node_name.c_str(), var_name.c_str());
+     377           0 :     return false;
+     378             :   }
+     379             : 
+     380        8286 :   if (!std::isfinite(msg.velocity.angular.z)) {
+     381           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.angular.z'!!!", node_name.c_str(), var_name.c_str());
+     382           0 :     return false;
+     383             :   }
+     384             : 
+     385             :   // check linear acceleration
+     386             : 
+     387        8286 :   if (!std::isfinite(msg.acceleration.linear.x)) {
+     388           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.linear.x'!!!", node_name.c_str(), var_name.c_str());
+     389           0 :     return false;
+     390             :   }
+     391             : 
+     392        8286 :   if (!std::isfinite(msg.acceleration.linear.y)) {
+     393           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.linear.y'!!!", node_name.c_str(), var_name.c_str());
+     394           0 :     return false;
+     395             :   }
+     396             : 
+     397        8286 :   if (!std::isfinite(msg.acceleration.linear.z)) {
+     398           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.linear.z'!!!", node_name.c_str(), var_name.c_str());
+     399           0 :     return false;
+     400             :   }
+     401             : 
+     402             :   // check angular acceleration
+     403             : 
+     404        8286 :   if (!std::isfinite(msg.acceleration.angular.x)) {
+     405           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.angular.x'!!!", node_name.c_str(), var_name.c_str());
+     406           0 :     return false;
+     407             :   }
+     408             : 
+     409        8286 :   if (!std::isfinite(msg.acceleration.angular.y)) {
+     410           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.angular.y'!!!", node_name.c_str(), var_name.c_str());
+     411           0 :     return false;
+     412             :   }
+     413             : 
+     414        8286 :   if (!std::isfinite(msg.acceleration.angular.z)) {
+     415           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.angular.z'!!!", node_name.c_str(), var_name.c_str());
+     416           0 :     return false;
+     417             :   }
+     418             : 
+     419             :   // check acceleration angular disturbance
+     420             : 
+     421        8286 :   if (!std::isfinite(msg.acceleration_disturbance.angular.x)) {
+     422           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration_disturbance.angular.x'!!!", node_name.c_str(), var_name.c_str());
+     423           0 :     return false;
+     424             :   }
+     425             : 
+     426        8286 :   if (!std::isfinite(msg.acceleration_disturbance.angular.y)) {
+     427           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration_disturbance.angular.y'!!!", node_name.c_str(), var_name.c_str());
+     428           0 :     return false;
+     429             :   }
+     430             : 
+     431        8286 :   if (!std::isfinite(msg.acceleration_disturbance.angular.z)) {
+     432           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration_disturbance.angular.z'!!!", node_name.c_str(), var_name.c_str());
+     433           0 :     return false;
+     434             :   }
+     435             : 
+     436             :   // check acceleration linear disturbance
+     437             : 
+     438        8286 :   if (!std::isfinite(msg.acceleration_disturbance.linear.x)) {
+     439           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration_disturbance.linear.x'!!!", node_name.c_str(), var_name.c_str());
+     440           0 :     return false;
+     441             :   }
+     442             : 
+     443        8286 :   if (!std::isfinite(msg.acceleration_disturbance.linear.y)) {
+     444           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration_disturbance.linear.y'!!!", node_name.c_str(), var_name.c_str());
+     445           0 :     return false;
+     446             :   }
+     447             : 
+     448        8286 :   if (!std::isfinite(msg.acceleration_disturbance.linear.z)) {
+     449           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration_disturbance.linear.z'!!!", node_name.c_str(), var_name.c_str());
+     450           0 :     return false;
+     451             :   }
+     452             : 
+     453        8286 :   return true;
+     454             : }
+     455             : 
+     456             : //}
+     457             : 
+     458             : /* RCChannelToRange() //{ */
+     459             : 
+     460           0 : double RCChannelToRange(double rc_value, double range, double deadband) {
+     461             : 
+     462           0 :   double tmp_neg1_to_1 = (rc_value - 0.5) * 2.0;
+     463             : 
+     464           0 :   if (tmp_neg1_to_1 > 1.0) {
+     465           0 :     tmp_neg1_to_1 = 1.0;
+     466           0 :   } else if (tmp_neg1_to_1 < -1.0) {
+     467           0 :     tmp_neg1_to_1 = -1.0;
+     468             :   }
+     469             : 
+     470             :   // check the deadband
+     471           0 :   if (tmp_neg1_to_1 < deadband && tmp_neg1_to_1 > -deadband) {
+     472           0 :     return 0.0;
+     473             :   }
+     474             : 
+     475           0 :   if (tmp_neg1_to_1 > 0) {
+     476             : 
+     477           0 :     double tmp = (tmp_neg1_to_1 - deadband) / (1.0 - deadband);
+     478             : 
+     479           0 :     return range * tmp;
+     480             : 
+     481             :   } else {
+     482             : 
+     483           0 :     double tmp = (-tmp_neg1_to_1 - deadband) / (1.0 - deadband);
+     484             : 
+     485           0 :     return -range * tmp;
+     486             :   }
+     487             : 
+     488             :   return 0.0;
+     489             : }
+     490             : 
+     491             : //}
+     492             : 
+     493             : /* loadDetailedUavModelParams() //{ */
+     494             : 
+     495           7 : std::optional<DetailedModelParams_t> loadDetailedUavModelParams(ros::NodeHandle& nh, const std::string& node_name, const std::string& platform_config,
+     496             :                                                                 const std::string& custom_config) {
+     497             : 
+     498          14 :   mrs_lib::ParamLoader param_loader(nh, node_name);
+     499             : 
+     500           7 :   if (custom_config != "") {
+     501           7 :     param_loader.addYamlFile(custom_config);
+     502             :   }
+     503             : 
+     504           7 :   if (platform_config != "") {
+     505           7 :     param_loader.addYamlFile(platform_config);
+     506             :   }
+     507             : 
+     508             :   double arm_length;
+     509             :   double body_height;
+     510             :   double force_constant;
+     511             :   double torque_constant;
+     512             :   double prop_radius;
+     513             :   double rpm_min;
+     514             :   double rpm_max;
+     515             :   double mass;
+     516             : 
+     517           7 :   param_loader.loadParam("uav_mass", mass);
+     518             : 
+     519           7 :   param_loader.loadParam("model_params/arm_length", arm_length);
+     520           7 :   param_loader.loadParam("model_params/body_height", body_height);
+     521             : 
+     522           7 :   param_loader.loadParam("model_params/propulsion/force_constant", force_constant);
+     523           7 :   param_loader.loadParam("model_params/propulsion/torque_constant", torque_constant);
+     524           7 :   param_loader.loadParam("model_params/propulsion/prop_radius", prop_radius);
+     525           7 :   param_loader.loadParam("model_params/propulsion/rpm/min", rpm_min);
+     526           7 :   param_loader.loadParam("model_params/propulsion/rpm/max", rpm_max);
+     527             : 
+     528          21 :   Eigen::MatrixXd allocation_matrix = param_loader.loadMatrixDynamic2("model_params/propulsion/allocation_matrix", 4, -1);
+     529             : 
+     530           7 :   if (!param_loader.loadedSuccessfully()) {
+     531           0 :     ROS_INFO("[%s]: detailed model params not loaded, missing some info", node_name.c_str());
+     532           0 :     return {};
+     533             :   }
+     534             : 
+     535           7 :   int n_motors = allocation_matrix.cols();
+     536             : 
+     537          14 :   DetailedModelParams_t model_params;
+     538             : 
+     539           7 :   model_params.arm_length  = arm_length;
+     540           7 :   model_params.body_height = body_height;
+     541           7 :   model_params.prop_radius = prop_radius;
+     542             : 
+     543          21 :   Eigen::MatrixXd inertia_matrix = param_loader.loadMatrixDynamic2("model_params/inertia_matrix", 3, 3);
+     544             : 
+     545           7 :   if (param_loader.loadedSuccessfully()) {
+     546             : 
+     547           0 :     model_params.inertia = inertia_matrix;
+     548           0 :     ROS_INFO("[%s]: inertia loaded from config file:", node_name.c_str());
+     549           0 :     ROS_INFO_STREAM(model_params.inertia);
+     550             : 
+     551             :   } else {
+     552             : 
+     553             :     // create the inertia matrix
+     554           7 :     model_params.inertia       = Eigen::Matrix3d::Zero();
+     555           7 :     model_params.inertia(0, 0) = mass * (3.0 * arm_length * arm_length + body_height * body_height) / 12.0;
+     556           7 :     model_params.inertia(1, 1) = mass * (3.0 * arm_length * arm_length + body_height * body_height) / 12.0;
+     557           7 :     model_params.inertia(2, 2) = (mass * arm_length * arm_length) / 2.0;
+     558             : 
+     559           7 :     ROS_INFO("[%s]: inertia computed form parameters:", node_name.c_str());
+     560           7 :     ROS_INFO_STREAM(model_params.inertia);
+     561             :   }
+     562             : 
+     563             :   // create the force-torque allocation matrix
+     564           7 :   model_params.force_torque_mixer = allocation_matrix;
+     565           7 :   model_params.force_torque_mixer.row(0) *= arm_length * force_constant;
+     566           7 :   model_params.force_torque_mixer.row(1) *= arm_length * force_constant;
+     567           7 :   model_params.force_torque_mixer.row(2) *= torque_constant * (3.0 * prop_radius) * force_constant;
+     568           7 :   model_params.force_torque_mixer.row(3) *= force_constant;
+     569             : 
+     570             :   // | ------- create the control group allocation matrix ------- |
+     571             : 
+     572             :   // pseudoinverse of the force-torque matrix (maximum norm)
+     573             :   Eigen::MatrixXd alloc_tmp =
+     574          14 :       model_params.force_torque_mixer.transpose() * (model_params.force_torque_mixer * model_params.force_torque_mixer.transpose()).inverse();
+     575             : 
+     576             :   // | ------------- normalize the allocation matrix ------------ |
+     577             :   // this will make it match the PX4 control group mixing
+     578             : 
+     579             :   // the first two columns (roll, pitch)
+     580          35 :   for (int i = 0; i < n_motors; i++) {
+     581          28 :     alloc_tmp.block(i, 0, 1, 2).normalize();
+     582             :   }
+     583             : 
+     584             :   // the 3rd column (yaw)
+     585          35 :   for (int i = 0; i < n_motors; i++) {
+     586          28 :     if (alloc_tmp(i, 2) > 1e-2) {
+     587          14 :       alloc_tmp(i, 2) = 1.0;
+     588          14 :     } else if (alloc_tmp(i, 2) < -1e-2) {
+     589          14 :       alloc_tmp(i, 2) = -1.0;
+     590             :     } else {
+     591           0 :       alloc_tmp(i, 2) = 0.0;
+     592             :     }
+     593             :   }
+     594             : 
+     595             :   // the 4th column (throttle)
+     596          35 :   for (int i = 0; i < n_motors; i++) {
+     597          28 :     alloc_tmp(i, 3) = 1.0;
+     598             :   }
+     599             : 
+     600           7 :   std::cout << "Control group mixer: " << std::endl << alloc_tmp << std::endl;
+     601             : 
+     602           7 :   model_params.control_group_mixer = alloc_tmp;
+     603             : 
+     604           7 :   return model_params;
+     605             : }
+     606             : 
+     607             : //}
+     608             : 
+     609             : /* getLowestOutput() //{ */
+     610             : 
+     611         473 : CONTROL_OUTPUT getLowestOuput(const ControlOutputModalities_t& outputs) {
+     612             : 
+     613         473 :   if (outputs.actuators) {
+     614           0 :     return ACTUATORS_CMD;
+     615             :   }
+     616             : 
+     617         473 :   if (outputs.control_group) {
+     618           0 :     return CONTROL_GROUP;
+     619             :   }
+     620             : 
+     621         473 :   if (outputs.attitude_rate) {
+     622         473 :     return ATTITUDE_RATE;
+     623             :   }
+     624             : 
+     625           0 :   if (outputs.attitude) {
+     626           0 :     return ATTITUDE;
+     627             :   }
+     628             : 
+     629           0 :   if (outputs.acceleration_hdg_rate) {
+     630           0 :     return ACCELERATION_HDG_RATE;
+     631             :   }
+     632             : 
+     633           0 :   if (outputs.acceleration_hdg) {
+     634           0 :     return ACCELERATION_HDG;
+     635             :   }
+     636             : 
+     637           0 :   if (outputs.velocity_hdg_rate) {
+     638           0 :     return VELOCITY_HDG_RATE;
+     639             :   }
+     640             : 
+     641           0 :   if (outputs.velocity_hdg) {
+     642           0 :     return VELOCITY_HDG;
+     643             :   }
+     644             : 
+     645           0 :   return POSITION;
+     646             : }
+     647             : 
+     648             : //}
+     649             : 
+     650             : /* getHighestOutput() //{ */
+     651             : 
+     652           0 : CONTROL_OUTPUT getHighestOuput(const ControlOutputModalities_t& outputs) {
+     653             : 
+     654           0 :   if (outputs.position) {
+     655           0 :     return POSITION;
+     656             :   }
+     657             : 
+     658           0 :   if (outputs.velocity_hdg) {
+     659           0 :     return VELOCITY_HDG;
+     660             :   }
+     661             : 
+     662           0 :   if (outputs.velocity_hdg_rate) {
+     663           0 :     return VELOCITY_HDG_RATE;
+     664             :   }
+     665             : 
+     666           0 :   if (outputs.acceleration_hdg) {
+     667           0 :     return ACCELERATION_HDG;
+     668             :   }
+     669             : 
+     670           0 :   if (outputs.acceleration_hdg_rate) {
+     671           0 :     return ACCELERATION_HDG_RATE;
+     672             :   }
+     673             : 
+     674           0 :   if (outputs.attitude) {
+     675           0 :     return ATTITUDE;
+     676             :   }
+     677             : 
+     678           0 :   if (outputs.attitude_rate) {
+     679           0 :     return ATTITUDE_RATE;
+     680             :   }
+     681             : 
+     682           0 :   if (outputs.control_group) {
+     683           0 :     return CONTROL_GROUP;
+     684             :   }
+     685             : 
+     686           0 :   return ACTUATORS_CMD;
+     687             : }
+     688             : 
+     689             : //}
+     690             : 
+     691             : // | -------- extraction of throttle out of hw api cmds ------- |
+     692             : 
+     693             : /* extractThrottle() //{ */
+     694             : 
+     695        9635 : std::optional<double> extractThrottle(const Controller::ControlOutput& control_output) {
+     696             : 
+     697        9635 :   if (!control_output.control_output) {
+     698         908 :     return {};
+     699             :   }
+     700             : 
+     701       17454 :   return std::visit(HwApiCmdExtractThrottleVisitor(), control_output.control_output.value());
+     702             : }
+     703             : 
+     704             : //}
+     705             : 
+     706             : // | -------------- validation of HW api commands ------------- |
+     707             : 
+     708             : /* validateControlOutput() //{ */
+     709             : 
+     710        6863 : bool validateControlOutput(const Controller::ControlOutput& control_output, const ControlOutputModalities_t& output_modalities, const std::string& node_name,
+     711             :                            const std::string& var_name) {
+     712             : 
+     713        6863 :   if (!control_output.control_output) {
+     714           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: the optional variable '%s' is not set!!!", node_name.c_str(), var_name.c_str());
+     715           0 :     return false;
+     716             :   }
+     717             : 
+     718        6863 :   std::variant<ControlOutputModalities_t> output_modalities_var{output_modalities};
+     719       13726 :   std::variant<std::string>               node_name_var{node_name};
+     720        6863 :   std::variant<std::string>               var_name_var{var_name};
+     721             : 
+     722        6863 :   return std::visit(HwApiValidateVisitor(), control_output.control_output.value(), output_modalities_var, node_name_var, var_name_var);
+     723             : }
+     724             : 
+     725             : //}
+     726             : 
+     727             : /* validateHwApiActuatorCmd() //{ */
+     728             : 
+     729           0 : bool validateHwApiActuatorCmd(const mrs_msgs::HwApiActuatorCmd& msg, const std::string& node_name, const std::string& var_name) {
+     730             : 
+     731           0 :   for (size_t i = 0; i < msg.motors.size(); i++) {
+     732           0 :     if (!std::isfinite(msg.motors[i])) {
+     733           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.motors[%d]'!!!", node_name.c_str(), var_name.c_str(), int(i));
+     734           0 :       return false;
+     735             :     }
+     736             :   }
+     737             : 
+     738           0 :   return true;
+     739             : }
+     740             : 
+     741             : //}
+     742             : 
+     743             : /* validateHwApiControlGroupCmd() //{ */
+     744             : 
+     745           0 : bool validateHwApiControlGroupCmd(const mrs_msgs::HwApiControlGroupCmd& msg, const std::string& node_name, const std::string& var_name) {
+     746             : 
+     747           0 :   if (!std::isfinite(msg.roll)) {
+     748           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.roll'!!!", node_name.c_str(), var_name.c_str());
+     749           0 :     return false;
+     750             :   }
+     751             : 
+     752           0 :   if (!std::isfinite(msg.pitch)) {
+     753           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.pitch'!!!", node_name.c_str(), var_name.c_str());
+     754           0 :     return false;
+     755             :   }
+     756             : 
+     757           0 :   if (!std::isfinite(msg.yaw)) {
+     758           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.yaw'!!!", node_name.c_str(), var_name.c_str());
+     759           0 :     return false;
+     760             :   }
+     761             : 
+     762           0 :   if (!std::isfinite(msg.throttle)) {
+     763           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.throttle'!!!", node_name.c_str(), var_name.c_str());
+     764           0 :     return false;
+     765             :   }
+     766             : 
+     767           0 :   return true;
+     768             : }
+     769             : 
+     770             : //}
+     771             : 
+     772             : /* validateHwApiAttitudeCmd() //{ */
+     773             : 
+     774        8297 : bool validateHwApiAttitudeCmd(const mrs_msgs::HwApiAttitudeCmd& msg, const std::string& node_name, const std::string& var_name) {
+     775             : 
+     776             :   // check the orientation
+     777             : 
+     778        8297 :   if (!std::isfinite(msg.orientation.x)) {
+     779           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.orientation.x'!!!", node_name.c_str(), var_name.c_str());
+     780           0 :     return false;
+     781             :   }
+     782             : 
+     783        8297 :   if (!std::isfinite(msg.orientation.y)) {
+     784           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.orientation.y'!!!", node_name.c_str(), var_name.c_str());
+     785           0 :     return false;
+     786             :   }
+     787             : 
+     788        8297 :   if (!std::isfinite(msg.orientation.z)) {
+     789           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.orientation.z'!!!", node_name.c_str(), var_name.c_str());
+     790           0 :     return false;
+     791             :   }
+     792             : 
+     793        8297 :   if (!std::isfinite(msg.orientation.w)) {
+     794           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.orientation.w'!!!", node_name.c_str(), var_name.c_str());
+     795           0 :     return false;
+     796             :   }
+     797             : 
+     798             :   // check the throttle
+     799             : 
+     800        8297 :   if (!std::isfinite(msg.throttle)) {
+     801           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.throttle'!!!", node_name.c_str(), var_name.c_str());
+     802           0 :     return false;
+     803             :   }
+     804             : 
+     805        8297 :   return true;
+     806             : }
+     807             : 
+     808             : //}
+     809             : 
+     810             : /* validateHwApiAttitudeRateCmd() //{ */
+     811             : 
+     812        5428 : bool validateHwApiAttitudeRateCmd(const mrs_msgs::HwApiAttitudeRateCmd& msg, const std::string& node_name, const std::string& var_name) {
+     813             : 
+     814             :   // check the body rate
+     815             : 
+     816        5428 :   if (!std::isfinite(msg.body_rate.x)) {
+     817           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.body_rate.x'!!!", node_name.c_str(), var_name.c_str());
+     818           0 :     return false;
+     819             :   }
+     820             : 
+     821        5428 :   if (!std::isfinite(msg.body_rate.y)) {
+     822           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.body_rate.y'!!!", node_name.c_str(), var_name.c_str());
+     823           0 :     return false;
+     824             :   }
+     825             : 
+     826        5428 :   if (!std::isfinite(msg.body_rate.z)) {
+     827           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.body_rate.z'!!!", node_name.c_str(), var_name.c_str());
+     828           0 :     return false;
+     829             :   }
+     830             : 
+     831             :   // check the throttle
+     832             : 
+     833        5428 :   if (!std::isfinite(msg.throttle)) {
+     834           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.throttle'!!!", node_name.c_str(), var_name.c_str());
+     835           0 :     return false;
+     836             :   }
+     837             : 
+     838        5428 :   return true;
+     839             : }
+     840             : 
+     841             : //}
+     842             : 
+     843             : /* validateHwApiAccelerationHdgRateCmd() //{ */
+     844             : 
+     845           0 : bool validateHwApiAccelerationHdgRateCmd(const mrs_msgs::HwApiAccelerationHdgRateCmd& msg, const std::string& node_name, const std::string& var_name) {
+     846             : 
+     847             :   // | ----------------- check the acceleration ----------------- |
+     848             : 
+     849           0 :   if (!std::isfinite(msg.acceleration.x)) {
+     850           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.x'!!!", node_name.c_str(), var_name.c_str());
+     851           0 :     return false;
+     852             :   }
+     853             : 
+     854           0 :   if (!std::isfinite(msg.acceleration.y)) {
+     855           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.y'!!!", node_name.c_str(), var_name.c_str());
+     856           0 :     return false;
+     857             :   }
+     858             : 
+     859           0 :   if (!std::isfinite(msg.acceleration.z)) {
+     860           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.z'!!!", node_name.c_str(), var_name.c_str());
+     861           0 :     return false;
+     862             :   }
+     863             : 
+     864             :   // check the heading rate
+     865             : 
+     866           0 :   if (!std::isfinite(msg.heading_rate)) {
+     867           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading_rate'!!!", node_name.c_str(), var_name.c_str());
+     868           0 :     return false;
+     869             :   }
+     870             : 
+     871           0 :   return true;
+     872             : }
+     873             : 
+     874             : //}
+     875             : 
+     876             : /* validateHwApiAccelerationHdgCmd() //{ */
+     877             : 
+     878           0 : bool validateHwApiAccelerationHdgCmd(const mrs_msgs::HwApiAccelerationHdgCmd& msg, const std::string& node_name, const std::string& var_name) {
+     879             : 
+     880             :   // | ----------------- check the acceleration ----------------- |
+     881             : 
+     882           0 :   if (!std::isfinite(msg.acceleration.x)) {
+     883           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.x'!!!", node_name.c_str(), var_name.c_str());
+     884           0 :     return false;
+     885             :   }
+     886             : 
+     887           0 :   if (!std::isfinite(msg.acceleration.y)) {
+     888           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.y'!!!", node_name.c_str(), var_name.c_str());
+     889           0 :     return false;
+     890             :   }
+     891             : 
+     892           0 :   if (!std::isfinite(msg.acceleration.z)) {
+     893           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.acceleration.z'!!!", node_name.c_str(), var_name.c_str());
+     894           0 :     return false;
+     895             :   }
+     896             : 
+     897             :   // check the heading
+     898             : 
+     899           0 :   if (!std::isfinite(msg.heading)) {
+     900           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading'!!!", node_name.c_str(), var_name.c_str());
+     901           0 :     return false;
+     902             :   }
+     903             : 
+     904           0 :   return true;
+     905             : }
+     906             : 
+     907             : //}
+     908             : 
+     909             : /* validateHwApiVelocityHdgRateCmd() //{ */
+     910             : 
+     911           0 : bool validateHwApiVelocityHdgRateCmd(const mrs_msgs::HwApiVelocityHdgRateCmd& msg, const std::string& node_name, const std::string& var_name) {
+     912             : 
+     913             :   // | ----------------- check the velocity ----------------- |
+     914             : 
+     915           0 :   if (!std::isfinite(msg.velocity.x)) {
+     916           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.x'!!!", node_name.c_str(), var_name.c_str());
+     917           0 :     return false;
+     918             :   }
+     919             : 
+     920           0 :   if (!std::isfinite(msg.velocity.y)) {
+     921           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.y'!!!", node_name.c_str(), var_name.c_str());
+     922           0 :     return false;
+     923             :   }
+     924             : 
+     925           0 :   if (!std::isfinite(msg.velocity.z)) {
+     926           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.z'!!!", node_name.c_str(), var_name.c_str());
+     927           0 :     return false;
+     928             :   }
+     929             : 
+     930             :   // check the heading rate
+     931             : 
+     932           0 :   if (!std::isfinite(msg.heading_rate)) {
+     933           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading_rate'!!!", node_name.c_str(), var_name.c_str());
+     934           0 :     return false;
+     935             :   }
+     936             : 
+     937           0 :   return true;
+     938             : }
+     939             : 
+     940             : //}
+     941             : 
+     942             : /* validateHwApiVelocityHdgCmd() //{ */
+     943             : 
+     944           0 : bool validateHwApiVelocityHdgCmd(const mrs_msgs::HwApiVelocityHdgCmd& msg, const std::string& node_name, const std::string& var_name) {
+     945             : 
+     946             :   // | ----------------- check the velocity ----------------- |
+     947             : 
+     948           0 :   if (!std::isfinite(msg.velocity.x)) {
+     949           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.x'!!!", node_name.c_str(), var_name.c_str());
+     950           0 :     return false;
+     951             :   }
+     952             : 
+     953           0 :   if (!std::isfinite(msg.velocity.y)) {
+     954           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.y'!!!", node_name.c_str(), var_name.c_str());
+     955           0 :     return false;
+     956             :   }
+     957             : 
+     958           0 :   if (!std::isfinite(msg.velocity.z)) {
+     959           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.velocity.z'!!!", node_name.c_str(), var_name.c_str());
+     960           0 :     return false;
+     961             :   }
+     962             : 
+     963             :   // check the heading
+     964             : 
+     965           0 :   if (!std::isfinite(msg.heading)) {
+     966           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading'!!!", node_name.c_str(), var_name.c_str());
+     967           0 :     return false;
+     968             :   }
+     969             : 
+     970           0 :   return true;
+     971             : }
+     972             : 
+     973             : //}
+     974             : 
+     975             : /* validateHwApiPositionHdgCmd() //{ */
+     976             : 
+     977           0 : bool validateHwApiPositionCmd(const mrs_msgs::HwApiPositionCmd& msg, const std::string& node_name, const std::string& var_name) {
+     978             : 
+     979             :   // | ----------------- check the position ----------------- |
+     980             : 
+     981           0 :   if (!std::isfinite(msg.position.x)) {
+     982           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.position.x'!!!", node_name.c_str(), var_name.c_str());
+     983           0 :     return false;
+     984             :   }
+     985             : 
+     986           0 :   if (!std::isfinite(msg.position.y)) {
+     987           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.position.y'!!!", node_name.c_str(), var_name.c_str());
+     988           0 :     return false;
+     989             :   }
+     990             : 
+     991           0 :   if (!std::isfinite(msg.position.z)) {
+     992           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.position.z'!!!", node_name.c_str(), var_name.c_str());
+     993           0 :     return false;
+     994             :   }
+     995             : 
+     996             :   // check the heading
+     997             : 
+     998           0 :   if (!std::isfinite(msg.heading)) {
+     999           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in variable '%s.heading'!!!", node_name.c_str(), var_name.c_str());
+    1000           0 :     return false;
+    1001             :   }
+    1002             : 
+    1003           0 :   return true;
+    1004             : }
+    1005             : 
+    1006             : //}
+    1007             : 
+    1008             : // | ------------ initialization of HW api commands ----------- |
+    1009             : 
+    1010             : /* initializeDefaultOutput() //{ */
+    1011             : 
+    1012         438 : Controller::HwApiOutputVariant initializeDefaultOutput(const ControlOutputModalities_t& possible_outputs, const mrs_msgs::UavState& uav_state,
+    1013             :                                                        const double& min_throttle, const double& n_motors) {
+    1014             : 
+    1015         438 :   CONTROL_OUTPUT lowest_output = getLowestOuput(possible_outputs);
+    1016             : 
+    1017         438 :   Controller::HwApiOutputVariant output;
+    1018             : 
+    1019         438 :   switch (lowest_output) {
+    1020           0 :     case ACTUATORS_CMD: {
+    1021           0 :       output = mrs_msgs::HwApiActuatorCmd();
+    1022           0 :       break;
+    1023             :     }
+    1024           0 :     case CONTROL_GROUP: {
+    1025           0 :       output = mrs_msgs::HwApiControlGroupCmd();
+    1026           0 :       break;
+    1027             :     }
+    1028         438 :     case ATTITUDE_RATE: {
+    1029         438 :       output = mrs_msgs::HwApiAttitudeRateCmd();
+    1030         438 :       break;
+    1031             :     }
+    1032           0 :     case ATTITUDE: {
+    1033           0 :       output = mrs_msgs::HwApiAttitudeCmd();
+    1034           0 :       break;
+    1035             :     }
+    1036           0 :     case ACCELERATION_HDG_RATE: {
+    1037           0 :       output = mrs_msgs::HwApiAccelerationHdgRateCmd();
+    1038           0 :       break;
+    1039             :     }
+    1040           0 :     case ACCELERATION_HDG: {
+    1041           0 :       output = mrs_msgs::HwApiAccelerationHdgCmd();
+    1042           0 :       break;
+    1043             :     }
+    1044           0 :     case VELOCITY_HDG_RATE: {
+    1045           0 :       output = mrs_msgs::HwApiVelocityHdgRateCmd();
+    1046           0 :       break;
+    1047             :     }
+    1048           0 :     case VELOCITY_HDG: {
+    1049           0 :       output = mrs_msgs::HwApiVelocityHdgCmd();
+    1050           0 :       break;
+    1051             :     }
+    1052           0 :     case POSITION: {
+    1053           0 :       output = mrs_msgs::HwApiPositionCmd();
+    1054           0 :       break;
+    1055             :     }
+    1056             :   }
+    1057             : 
+    1058         876 :   std::variant<mrs_msgs::UavState> uav_state_var{uav_state};
+    1059         438 :   std::variant<double>             min_throttle_var{min_throttle};
+    1060         438 :   std::variant<double>             n_motors_var{n_motors};
+    1061             : 
+    1062         438 :   std::visit(HwApiInitializeVisitor(), output, uav_state_var, min_throttle_var, n_motors_var);
+    1063             : 
+    1064         876 :   return output;
+    1065             : }  // namespace mrs_uav_managers
+    1066             : 
+    1067             : //}
+    1068             : 
+    1069             : /* initializeHwApiCmd(mrs_msgs::HwApiActuatorCmd& msg) //{ */
+    1070             : 
+    1071           0 : void initializeHwApiCmd(mrs_msgs::HwApiActuatorCmd& msg, const double& min_throttle, const double& n_motors) {
+    1072             : 
+    1073           0 :   msg.stamp = ros::Time::now();
+    1074             : 
+    1075           0 :   for (int i = 0; i < n_motors; i++) {
+    1076           0 :     msg.motors.push_back(min_throttle);
+    1077             :   }
+    1078           0 : }
+    1079             : 
+    1080             : //}
+    1081             : 
+    1082             : /* initializeHwApiCmd(mrs_msgs::HwApiControlGroupCmd& msg) //{ */
+    1083             : 
+    1084           0 : void initializeHwApiCmd(mrs_msgs::HwApiControlGroupCmd& msg, const double& min_throttle) {
+    1085             : 
+    1086           0 :   msg.stamp = ros::Time::now();
+    1087             : 
+    1088           0 :   msg.roll     = 0;
+    1089           0 :   msg.pitch    = 0;
+    1090           0 :   msg.yaw      = 0;
+    1091           0 :   msg.throttle = min_throttle;
+    1092           0 : }
+    1093             : 
+    1094             : //}
+    1095             : 
+    1096             : /* initializeHwApiCmd(mrs_msgs::HwApiAttitudeRateCmd& msg) //{ */
+    1097             : 
+    1098         438 : void initializeHwApiCmd(mrs_msgs::HwApiAttitudeRateCmd& msg, const double& min_throttle) {
+    1099             : 
+    1100         438 :   msg.stamp = ros::Time::now();
+    1101             : 
+    1102         438 :   msg.body_rate.x = 0;
+    1103         438 :   msg.body_rate.y = 0;
+    1104         438 :   msg.body_rate.z = 0;
+    1105         438 :   msg.throttle    = min_throttle;
+    1106         438 : }
+    1107             : 
+    1108             : //}
+    1109             : 
+    1110             : /* initializeHwApiCmd(mrs_msgs::HwApiAttitudeCmd& msg) //{ */
+    1111             : 
+    1112           0 : void initializeHwApiCmd(mrs_msgs::HwApiAttitudeCmd& msg, const mrs_msgs::UavState& uav_state, const double& min_throttle) {
+    1113             : 
+    1114           0 :   msg.stamp = ros::Time::now();
+    1115             : 
+    1116           0 :   msg.orientation = uav_state.pose.orientation;
+    1117           0 :   msg.throttle    = min_throttle;
+    1118           0 : }
+    1119             : 
+    1120             : //}
+    1121             : 
+    1122             : /* initializeHwApiCmd(mrs_msgs::HwApiAccelerationHdgRateCmd& msg) //{ */
+    1123             : 
+    1124           0 : void initializeHwApiCmd(mrs_msgs::HwApiAccelerationHdgRateCmd& msg, const mrs_msgs::UavState& uav_state) {
+    1125             : 
+    1126           0 :   msg.header.frame_id = uav_state.header.frame_id;
+    1127           0 :   msg.header.stamp    = ros::Time::now();
+    1128             : 
+    1129           0 :   msg.acceleration.x = 0;
+    1130           0 :   msg.acceleration.y = 0;
+    1131           0 :   msg.acceleration.z = 0;
+    1132           0 :   msg.heading_rate   = 0;
+    1133           0 : }
+    1134             : 
+    1135             : //}
+    1136             : 
+    1137             : /* initializeHwApiCmd(mrs_msgs::HwApiAccelerationHdgCmd& msg) //{ */
+    1138             : 
+    1139           0 : void initializeHwApiCmd(mrs_msgs::HwApiAccelerationHdgCmd& msg, const mrs_msgs::UavState& uav_state) {
+    1140             : 
+    1141           0 :   msg.header.frame_id = uav_state.header.frame_id;
+    1142           0 :   msg.header.stamp    = ros::Time::now();
+    1143             : 
+    1144           0 :   msg.acceleration.x = 0;
+    1145           0 :   msg.acceleration.y = 0;
+    1146           0 :   msg.acceleration.z = 0;
+    1147             : 
+    1148             :   try {
+    1149           0 :     msg.heading = mrs_lib::AttitudeConverter(uav_state.pose.orientation).getHeading();
+    1150             :   }
+    1151           0 :   catch (std::runtime_error& exrun) {
+    1152           0 :     msg.heading = 0;
+    1153             :   }
+    1154           0 : }
+    1155             : 
+    1156             : //}
+    1157             : 
+    1158             : /* initializeHwApiCmd(mrs_msgs::HwApiVelocityHdgRateCmd& msg) //{ */
+    1159             : 
+    1160           0 : void initializeHwApiCmd(mrs_msgs::HwApiVelocityHdgRateCmd& msg, const mrs_msgs::UavState& uav_state) {
+    1161             : 
+    1162           0 :   msg.header.frame_id = uav_state.header.frame_id;
+    1163           0 :   msg.header.stamp    = ros::Time::now();
+    1164             : 
+    1165           0 :   msg.velocity.x   = 0;
+    1166           0 :   msg.velocity.y   = 0;
+    1167           0 :   msg.velocity.z   = 0;
+    1168           0 :   msg.heading_rate = 0;
+    1169           0 : }
+    1170             : 
+    1171             : //}
+    1172             : 
+    1173             : /* initializeHwApiCmd(mrs_msgs::HwApiVelocityHdgCmd& msg) //{ */
+    1174             : 
+    1175           0 : void initializeHwApiCmd(mrs_msgs::HwApiVelocityHdgCmd& msg, const mrs_msgs::UavState& uav_state) {
+    1176             : 
+    1177           0 :   msg.header.frame_id = uav_state.header.frame_id;
+    1178           0 :   msg.header.stamp    = ros::Time::now();
+    1179             : 
+    1180           0 :   msg.velocity.x = 0;
+    1181           0 :   msg.velocity.y = 0;
+    1182           0 :   msg.velocity.z = 0;
+    1183             : 
+    1184             :   try {
+    1185           0 :     msg.heading = mrs_lib::AttitudeConverter(uav_state.pose.orientation).getHeading();
+    1186             :   }
+    1187           0 :   catch (std::runtime_error& exrun) {
+    1188           0 :     msg.heading = 0;
+    1189             :   }
+    1190           0 : }
+    1191             : 
+    1192             : //}
+    1193             : 
+    1194             : /* initializeHwApiCmd(mrs_msgs::HwApiPositionCmd& msg) //{ */
+    1195             : 
+    1196           0 : void initializeHwApiCmd(mrs_msgs::HwApiPositionCmd& msg, const mrs_msgs::UavState& uav_state) {
+    1197             : 
+    1198           0 :   msg.header.frame_id = uav_state.header.frame_id;
+    1199           0 :   msg.header.stamp    = ros::Time::now();
+    1200             : 
+    1201           0 :   msg.position.x = uav_state.pose.position.x;
+    1202           0 :   msg.position.y = uav_state.pose.position.y;
+    1203           0 :   msg.position.z = uav_state.pose.position.z;
+    1204             : 
+    1205             :   try {
+    1206           0 :     msg.heading = mrs_lib::AttitudeConverter(uav_state.pose.orientation).getHeading();
+    1207             :   }
+    1208           0 :   catch (std::runtime_error& exrun) {
+    1209           0 :     msg.heading = 0;
+    1210             :   }
+    1211           0 : }
+    1212             : 
+    1213             : //}
+    1214             : 
+    1215             : }  // namespace control_manager
+    1216             : 
+    1217             : }  // namespace mrs_uav_managers
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/common/index-sort-f.html b/mrs_uav_managers/src/control_manager/common/index-sort-f.html new file mode 100644 index 0000000000..e1e3b04e5e --- /dev/null +++ b/mrs_uav_managers/src/control_manager/common/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/common + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager/commonHitTotalCoverage
Test:coverage.infoLines:15756327.9 %
Date:2023-11-29 14:09:54Functions:123138.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
common.cpp +
27.9%27.9%
+
27.9 %157 / 56338.7 %12 / 31
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/common/index-sort-l.html b/mrs_uav_managers/src/control_manager/common/index-sort-l.html new file mode 100644 index 0000000000..8dadd20d40 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/common/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/common + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager/commonHitTotalCoverage
Test:coverage.infoLines:15756327.9 %
Date:2023-11-29 14:09:54Functions:123138.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
common.cpp +
27.9%27.9%
+
27.9 %157 / 56338.7 %12 / 31
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/common/index.html b/mrs_uav_managers/src/control_manager/common/index.html new file mode 100644 index 0000000000..0fbeb41f3b --- /dev/null +++ b/mrs_uav_managers/src/control_manager/common/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/common + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager/commonHitTotalCoverage
Test:coverage.infoLines:15756327.9 %
Date:2023-11-29 14:09:54Functions:123138.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
common.cpp +
27.9%27.9%
+
27.9 %157 / 56338.7 %12 / 31
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/control_manager.cpp.func-sort-c.html b/mrs_uav_managers/src/control_manager/control_manager.cpp.func-sort-c.html new file mode 100644 index 0000000000..16539e554e --- /dev/null +++ b/mrs_uav_managers/src/control_manager/control_manager.cpp.func-sort-c.html @@ -0,0 +1,516 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/control_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager - control_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:1701366946.4 %
Date:2023-11-29 14:09:54Functions:5911153.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager14ControlManager11timerBumperERKN3ros10TimerEventE0
_ZN16mrs_uav_managers15control_manager14ControlManager12parachuteSrvEv0
_ZN16mrs_uav_managers15control_manager14ControlManager13callbackHoverERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager14callbackEHoverERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager14loadConfigFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_0
_ZN16mrs_uav_managers15control_manager14ControlManager14timerPirouetteERKN3ros10TimerEventE0
_ZN16mrs_uav_managers15control_manager14ControlManager15callbackGetMinZERN8mrs_msgs18GetFloat64Request_ISaIvEEERNS2_19GetFloat64Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager15callbackGotoFcuERN8mrs_msgs12Vec4Request_ISaIvEEERNS2_13Vec4Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager15deployParachuteB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager15timeoutUavStateERKd0
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackFailsafeERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackJoystickEN5boost10shared_ptrIKN11sensor_msgs4Joy_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackOdometryEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager17bumperGetSectorIdERKdS3_S3_0
_ZN16mrs_uav_managers15control_manager14ControlManager17callbackParachuteERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager17callbackPirouetteERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager18callbackSetHeadingERN8mrs_msgs12Vec1Request_ISaIvEEERNS2_13Vec1Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager18escalatingFailsafeB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager19callbackUseJoystickERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager19gotoTrajectoryStartB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackEnableBumperERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackGotoAltitudeERN8mrs_msgs12Vec1Request_ISaIvEEERNS2_13Vec1Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager20setVelocityReferenceB5cxx11ERKN8mrs_msgs25VelocityReferenceStamped_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager21callbackTransformPoseERN8mrs_msgs24TransformPoseSrvRequest_ISaIvEEERNS2_25TransformPoseSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager21callbackUseSafetyAreaERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager22bumperPushFromObstacleEv0
_ZN16mrs_uav_managers15control_manager14ControlManager22callbackReferenceTopicEN5boost10shared_ptrIKN8mrs_msgs17ReferenceStamped_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager22setTrajectoryReferenceB5cxx11EN8mrs_msgs20TrajectoryReference_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager22stopTrajectoryTrackingB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager23getNextEscFailsafeStateEv0
_ZN16mrs_uav_managers15control_manager14ControlManager23startTrajectoryTrackingB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager24callbackReferenceServiceERN8mrs_msgs27ReferenceStampedSrvRequest_ISaIvEEERNS2_28ReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager24callbackTransformVector3ERN8mrs_msgs27TransformVector3SrvRequest_ISaIvEEERNS2_28TransformVector3SrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager24resumeTrajectoryTrackingB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager25callbackValidateReferenceERN8mrs_msgs25ValidateReferenceRequest_ISaIvEEERNS2_26ValidateReferenceResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackEmergencyReferenceERN8mrs_msgs27ReferenceStampedSrvRequest_ISaIvEEERNS2_28ReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackFailsafeEscalatingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackSetHeadingRelativeERN8mrs_msgs12Vec1Request_ISaIvEEERNS2_13Vec1Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackTrackerResetStaticERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackTransformReferenceERN8mrs_msgs29TransformReferenceSrvRequest_ISaIvEEERNS2_30TransformReferenceSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager27callbackGotoTrajectoryStartERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager28velocityReferenceToReferenceERKN8mrs_msgs25VelocityReferenceStamped_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager29callbackValidateReferenceListERN8mrs_msgs29ValidateReferenceListRequest_ISaIvEEERNS2_30ValidateReferenceListResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager30callbackStopTrajectoryTrackingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager30callbackVelocityReferenceTopicEN5boost10shared_ptrIKN8mrs_msgs25VelocityReferenceStamped_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager31callbackStartTrajectoryTrackingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager32callbackResumeTrajectoryTrackingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager32callbackTrajectoryReferenceTopicEN5boost10shared_ptrIKN8mrs_msgs20TrajectoryReference_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager32callbackVelocityReferenceServiceERN8mrs_msgs35VelocityReferenceStampedSrvRequest_ISaIvEEERNS2_36VelocityReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager34callbackTrajectoryReferenceServiceERN8mrs_msgs30TrajectoryReferenceSrvRequest_ISaIvEEERNS2_31TrajectoryReferenceSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager5hoverB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager6ehoverB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager11callbackArmERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager12callbackGotoERN8mrs_msgs12Vec4Request_ISaIvEEERNS2_13Vec4Response_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager12setCallbacksEb1
_ZN16mrs_uav_managers15control_manager14ControlManager13callbackElandERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager23callbackEnableCallbacksERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager8failsafeB5cxx11Ev1
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackGotoRelativeERN8mrs_msgs12Vec4Request_ISaIvEEERNS2_13Vec4Response_IS4_EE2
_ZN16mrs_uav_managers15control_manager14ControlManager12setReferenceB5cxx11EN8mrs_msgs17ReferenceStamped_ISaIvEEE3
_ZN16mrs_uav_managers15control_manager14ControlManager27isPathToPointInSafetyArea3dERKN8mrs_msgs17ReferenceStamped_ISaIvEEES7_3
_ZN16mrs_uav_managers15control_manager14ControlManager5elandB5cxx11Ev3
_ZN16mrs_uav_managers15control_manager14ControlManager8elandSrvEv3
_ZN16mrs_uav_managers15control_manager14ControlManager20odometryCallbacksSrvEb4
_ZN16mrs_uav_managers15control_manager14ControlManager10isOffboardEv5
_ZN16mrs_uav_managers15control_manager14ControlManager21isPointInSafetyArea3dERKN8mrs_msgs17ReferenceStamped_ISaIvEEE5
_ZN16mrs_uav_managers15control_manager14ControlManager6armingB5cxx11Eb5
_ZN16mrs_uav_managers15control_manager14ControlManager18changeLandingStateENS0_15LandingStates_tE6
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers15control_manager14ControlManager10initializeEv7
_ZN16mrs_uav_managers15control_manager14ControlManager13preinitializeEv7
_ZN16mrs_uav_managers15control_manager14ControlManager14setConstraintsERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE7
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackToggleOutputERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE7
_ZN16mrs_uav_managers15control_manager14ControlManager22callbackSetConstraintsERN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEERNS2_31DynamicsConstraintsSrvResponse_IS4_EE7
_ZN16mrs_uav_managers15control_manager14ControlManager6onInitEv7
_ZN16mrs_uav_managers15control_manager14ControlManager8shutdownEv8
_ZN16mrs_uav_managers15control_manager14ControlManager22timerHwApiCapabilitiesERKN3ros10TimerEventE10
_ZN16mrs_uav_managers15control_manager14ControlManager12toggleOutputERKb15
_ZN16mrs_uav_managers15control_manager14ControlManager24callbackSwitchControllerERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE15
_ZN16mrs_uav_managers15control_manager14ControlManager21callbackSwitchTrackerERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE16
_ZN16mrs_uav_managers15control_manager14ControlManager23initializeControlOutputEv19
_ZN16mrs_uav_managers15control_manager14ControlManager16switchControllerERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE23
_ZN16mrs_uav_managers15control_manager14ControlManager13switchTrackerERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE24
_ZN16mrs_uav_managers15control_manager14ControlManager24setConstraintsToTrackersERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE24
_ZN16mrs_uav_managers15control_manager14ControlManager27setConstraintsToControllersERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE32
_ZN16mrs_uav_managers15control_manager16ControllerParamsC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_dddb35
_ZN16mrs_uav_managers15control_manager14ControlManager7getMassEv39
_ZN16mrs_uav_managers15control_manager13TrackerParamsC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_b42
_ZN16mrs_uav_managers15control_manager14ControlManager9ungripSrvEv111
_ZN16mrs_uav_managers15control_manager14ControlManager27isPathToPointInSafetyArea2dERKN8mrs_msgs17ReferenceStamped_ISaIvEEES7_157
_ZN16mrs_uav_managers15control_manager14ControlManager10timerElandERKN3ros10TimerEventE235
_ZN16mrs_uav_managers15control_manager14ControlManager27callbackValidateReference2dERN8mrs_msgs25ValidateReferenceRequest_ISaIvEEERNS2_26ValidateReferenceResponse_IS4_EE434
_ZN16mrs_uav_managers15control_manager14ControlManager7getMaxZERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE482
_ZN16mrs_uav_managers15control_manager14ControlManager21isPointInSafetyArea2dERKN8mrs_msgs17ReferenceStamped_ISaIvEEE666
_ZN16mrs_uav_managers15control_manager14ControlManager10callbackRCEN5boost10shared_ptrIKN8mrs_msgs16HwApiRcChannels_ISaIvEEEEE1073
_ZN16mrs_uav_managers15control_manager14ControlManager11timerStatusERKN3ros10TimerEventE1080
_ZN16mrs_uav_managers15control_manager14ControlManager16isFlyingNormallyEv1087
_ZN16mrs_uav_managers15control_manager14ControlManager18publishDiagnosticsEv1087
_ZN16mrs_uav_managers15control_manager14ControlManager13timerFailsafeERKN3ros10TimerEventE1398
_ZN16mrs_uav_managers15control_manager14ControlManager13timerJoystickERKN3ros10TimerEventE3247
_ZN16mrs_uav_managers15control_manager14ControlManager7getMinZERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE4017
_ZN16mrs_uav_managers15control_manager14ControlManager12callbackGNSSEN5boost10shared_ptrIKN11sensor_msgs10NavSatFix_ISaIvEEEEE5320
_ZN16mrs_uav_managers15control_manager14ControlManager29enforceControllersConstraintsERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE6810
_ZN16mrs_uav_managers15control_manager14ControlManager14updateTrackersEv6839
_ZN16mrs_uav_managers15control_manager14ControlManager17updateControllersERKN8mrs_msgs9UavState_ISaIvEEE8237
_ZN16mrs_uav_managers15control_manager14ControlManager27publishControlReferenceOdomERKSt8optionalIN8mrs_msgs15TrackerCommand_ISaIvEEEERKNS_10Controller13ControlOutputE8237
_ZN16mrs_uav_managers15control_manager14ControlManager7publishEv8237
_ZN16mrs_uav_managers15control_manager14ControlManager12asyncControlEv8285
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackUavStateEN5boost10shared_ptrIKN8mrs_msgs9UavState_ISaIvEEEEE8944
_ZN16mrs_uav_managers15control_manager14ControlManager11timerSafetyERKN3ros10TimerEventE17665
_ZN16mrs_uav_managers15control_manager14ControlManager19callbackHwApiStatusEN5boost10shared_ptrIKN8mrs_msgs12HwApiStatus_ISaIvEEEEE37869
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/control_manager.cpp.func.html b/mrs_uav_managers/src/control_manager/control_manager.cpp.func.html new file mode 100644 index 0000000000..9a14c116aa --- /dev/null +++ b/mrs_uav_managers/src/control_manager/control_manager.cpp.func.html @@ -0,0 +1,516 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/control_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager - control_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:1701366946.4 %
Date:2023-11-29 14:09:54Functions:5911153.2 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers15control_manager13TrackerParamsC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_b42
_ZN16mrs_uav_managers15control_manager14ControlManager10callbackRCEN5boost10shared_ptrIKN8mrs_msgs16HwApiRcChannels_ISaIvEEEEE1073
_ZN16mrs_uav_managers15control_manager14ControlManager10initializeEv7
_ZN16mrs_uav_managers15control_manager14ControlManager10isOffboardEv5
_ZN16mrs_uav_managers15control_manager14ControlManager10timerElandERKN3ros10TimerEventE235
_ZN16mrs_uav_managers15control_manager14ControlManager11callbackArmERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager11timerBumperERKN3ros10TimerEventE0
_ZN16mrs_uav_managers15control_manager14ControlManager11timerSafetyERKN3ros10TimerEventE17665
_ZN16mrs_uav_managers15control_manager14ControlManager11timerStatusERKN3ros10TimerEventE1080
_ZN16mrs_uav_managers15control_manager14ControlManager12asyncControlEv8285
_ZN16mrs_uav_managers15control_manager14ControlManager12callbackGNSSEN5boost10shared_ptrIKN11sensor_msgs10NavSatFix_ISaIvEEEEE5320
_ZN16mrs_uav_managers15control_manager14ControlManager12callbackGotoERN8mrs_msgs12Vec4Request_ISaIvEEERNS2_13Vec4Response_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager12parachuteSrvEv0
_ZN16mrs_uav_managers15control_manager14ControlManager12setCallbacksEb1
_ZN16mrs_uav_managers15control_manager14ControlManager12setReferenceB5cxx11EN8mrs_msgs17ReferenceStamped_ISaIvEEE3
_ZN16mrs_uav_managers15control_manager14ControlManager12toggleOutputERKb15
_ZN16mrs_uav_managers15control_manager14ControlManager13callbackElandERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager13callbackHoverERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager13preinitializeEv7
_ZN16mrs_uav_managers15control_manager14ControlManager13switchTrackerERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE24
_ZN16mrs_uav_managers15control_manager14ControlManager13timerFailsafeERKN3ros10TimerEventE1398
_ZN16mrs_uav_managers15control_manager14ControlManager13timerJoystickERKN3ros10TimerEventE3247
_ZN16mrs_uav_managers15control_manager14ControlManager14callbackEHoverERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager14loadConfigFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_0
_ZN16mrs_uav_managers15control_manager14ControlManager14setConstraintsERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE7
_ZN16mrs_uav_managers15control_manager14ControlManager14timerPirouetteERKN3ros10TimerEventE0
_ZN16mrs_uav_managers15control_manager14ControlManager14updateTrackersEv6839
_ZN16mrs_uav_managers15control_manager14ControlManager15callbackGetMinZERN8mrs_msgs18GetFloat64Request_ISaIvEEERNS2_19GetFloat64Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager15callbackGotoFcuERN8mrs_msgs12Vec4Request_ISaIvEEERNS2_13Vec4Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager15deployParachuteB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager15timeoutUavStateERKd0
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackFailsafeERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackJoystickEN5boost10shared_ptrIKN11sensor_msgs4Joy_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackOdometryEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager16callbackUavStateEN5boost10shared_ptrIKN8mrs_msgs9UavState_ISaIvEEEEE8944
_ZN16mrs_uav_managers15control_manager14ControlManager16isFlyingNormallyEv1087
_ZN16mrs_uav_managers15control_manager14ControlManager16switchControllerERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE23
_ZN16mrs_uav_managers15control_manager14ControlManager17bumperGetSectorIdERKdS3_S3_0
_ZN16mrs_uav_managers15control_manager14ControlManager17callbackParachuteERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager17callbackPirouetteERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager17updateControllersERKN8mrs_msgs9UavState_ISaIvEEE8237
_ZN16mrs_uav_managers15control_manager14ControlManager18callbackSetHeadingERN8mrs_msgs12Vec1Request_ISaIvEEERNS2_13Vec1Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager18changeLandingStateENS0_15LandingStates_tE6
_ZN16mrs_uav_managers15control_manager14ControlManager18escalatingFailsafeB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager18publishDiagnosticsEv1087
_ZN16mrs_uav_managers15control_manager14ControlManager19callbackHwApiStatusEN5boost10shared_ptrIKN8mrs_msgs12HwApiStatus_ISaIvEEEEE37869
_ZN16mrs_uav_managers15control_manager14ControlManager19callbackUseJoystickERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager19gotoTrajectoryStartB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackEnableBumperERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackGotoAltitudeERN8mrs_msgs12Vec1Request_ISaIvEEERNS2_13Vec1Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackGotoRelativeERN8mrs_msgs12Vec4Request_ISaIvEEERNS2_13Vec4Response_IS4_EE2
_ZN16mrs_uav_managers15control_manager14ControlManager20callbackToggleOutputERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE7
_ZN16mrs_uav_managers15control_manager14ControlManager20odometryCallbacksSrvEb4
_ZN16mrs_uav_managers15control_manager14ControlManager20setVelocityReferenceB5cxx11ERKN8mrs_msgs25VelocityReferenceStamped_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager21callbackSwitchTrackerERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE16
_ZN16mrs_uav_managers15control_manager14ControlManager21callbackTransformPoseERN8mrs_msgs24TransformPoseSrvRequest_ISaIvEEERNS2_25TransformPoseSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager21callbackUseSafetyAreaERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager21isPointInSafetyArea2dERKN8mrs_msgs17ReferenceStamped_ISaIvEEE666
_ZN16mrs_uav_managers15control_manager14ControlManager21isPointInSafetyArea3dERKN8mrs_msgs17ReferenceStamped_ISaIvEEE5
_ZN16mrs_uav_managers15control_manager14ControlManager22bumperPushFromObstacleEv0
_ZN16mrs_uav_managers15control_manager14ControlManager22callbackReferenceTopicEN5boost10shared_ptrIKN8mrs_msgs17ReferenceStamped_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager22callbackSetConstraintsERN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEERNS2_31DynamicsConstraintsSrvResponse_IS4_EE7
_ZN16mrs_uav_managers15control_manager14ControlManager22setTrajectoryReferenceB5cxx11EN8mrs_msgs20TrajectoryReference_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager22stopTrajectoryTrackingB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager22timerHwApiCapabilitiesERKN3ros10TimerEventE10
_ZN16mrs_uav_managers15control_manager14ControlManager23callbackEnableCallbacksERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE1
_ZN16mrs_uav_managers15control_manager14ControlManager23getNextEscFailsafeStateEv0
_ZN16mrs_uav_managers15control_manager14ControlManager23initializeControlOutputEv19
_ZN16mrs_uav_managers15control_manager14ControlManager23startTrajectoryTrackingB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager24callbackReferenceServiceERN8mrs_msgs27ReferenceStampedSrvRequest_ISaIvEEERNS2_28ReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager24callbackSwitchControllerERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE15
_ZN16mrs_uav_managers15control_manager14ControlManager24callbackTransformVector3ERN8mrs_msgs27TransformVector3SrvRequest_ISaIvEEERNS2_28TransformVector3SrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager24resumeTrajectoryTrackingB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager24setConstraintsToTrackersERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE24
_ZN16mrs_uav_managers15control_manager14ControlManager25callbackValidateReferenceERN8mrs_msgs25ValidateReferenceRequest_ISaIvEEERNS2_26ValidateReferenceResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackEmergencyReferenceERN8mrs_msgs27ReferenceStampedSrvRequest_ISaIvEEERNS2_28ReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackFailsafeEscalatingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackSetHeadingRelativeERN8mrs_msgs12Vec1Request_ISaIvEEERNS2_13Vec1Response_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackTrackerResetStaticERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager26callbackTransformReferenceERN8mrs_msgs29TransformReferenceSrvRequest_ISaIvEEERNS2_30TransformReferenceSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager27callbackGotoTrajectoryStartERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager27callbackValidateReference2dERN8mrs_msgs25ValidateReferenceRequest_ISaIvEEERNS2_26ValidateReferenceResponse_IS4_EE434
_ZN16mrs_uav_managers15control_manager14ControlManager27isPathToPointInSafetyArea2dERKN8mrs_msgs17ReferenceStamped_ISaIvEEES7_157
_ZN16mrs_uav_managers15control_manager14ControlManager27isPathToPointInSafetyArea3dERKN8mrs_msgs17ReferenceStamped_ISaIvEEES7_3
_ZN16mrs_uav_managers15control_manager14ControlManager27publishControlReferenceOdomERKSt8optionalIN8mrs_msgs15TrackerCommand_ISaIvEEEERKNS_10Controller13ControlOutputE8237
_ZN16mrs_uav_managers15control_manager14ControlManager27setConstraintsToControllersERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE32
_ZN16mrs_uav_managers15control_manager14ControlManager28velocityReferenceToReferenceERKN8mrs_msgs25VelocityReferenceStamped_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager29callbackValidateReferenceListERN8mrs_msgs29ValidateReferenceListRequest_ISaIvEEERNS2_30ValidateReferenceListResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager29enforceControllersConstraintsERKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEE6810
_ZN16mrs_uav_managers15control_manager14ControlManager30callbackStopTrajectoryTrackingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager30callbackVelocityReferenceTopicEN5boost10shared_ptrIKN8mrs_msgs25VelocityReferenceStamped_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager31callbackStartTrajectoryTrackingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager32callbackResumeTrajectoryTrackingERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager32callbackTrajectoryReferenceTopicEN5boost10shared_ptrIKN8mrs_msgs20TrajectoryReference_ISaIvEEEEE0
_ZN16mrs_uav_managers15control_manager14ControlManager32callbackVelocityReferenceServiceERN8mrs_msgs35VelocityReferenceStampedSrvRequest_ISaIvEEERNS2_36VelocityReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager34callbackTrajectoryReferenceServiceERN8mrs_msgs30TrajectoryReferenceSrvRequest_ISaIvEEERNS2_31TrajectoryReferenceSrvResponse_IS4_EE0
_ZN16mrs_uav_managers15control_manager14ControlManager5elandB5cxx11Ev3
_ZN16mrs_uav_managers15control_manager14ControlManager5hoverB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager6armingB5cxx11Eb5
_ZN16mrs_uav_managers15control_manager14ControlManager6ehoverB5cxx11Ev0
_ZN16mrs_uav_managers15control_manager14ControlManager6onInitEv7
_ZN16mrs_uav_managers15control_manager14ControlManager7getMassEv39
_ZN16mrs_uav_managers15control_manager14ControlManager7getMaxZERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE482
_ZN16mrs_uav_managers15control_manager14ControlManager7getMinZERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE4017
_ZN16mrs_uav_managers15control_manager14ControlManager7publishEv8237
_ZN16mrs_uav_managers15control_manager14ControlManager8elandSrvEv3
_ZN16mrs_uav_managers15control_manager14ControlManager8failsafeB5cxx11Ev1
_ZN16mrs_uav_managers15control_manager14ControlManager8shutdownEv8
_ZN16mrs_uav_managers15control_manager14ControlManager9ungripSrvEv111
_ZN16mrs_uav_managers15control_manager16ControllerParamsC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_dddb35
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/control_manager.cpp.gcov.html b/mrs_uav_managers/src/control_manager/control_manager.cpp.gcov.html new file mode 100644 index 0000000000..9a200b4ca4 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/control_manager.cpp.gcov.html @@ -0,0 +1,8811 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/control_manager.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager - control_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:1701366946.4 %
Date:2023-11-29 14:09:54Functions:5911153.2 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /* includes //{ */
+       2             : 
+       3             : #include <ros/ros.h>
+       4             : #include <ros/package.h>
+       5             : #include <nodelet/nodelet.h>
+       6             : 
+       7             : #include <mrs_uav_managers/control_manager/common.h>
+       8             : #include <control_manager/output_publisher.h>
+       9             : 
+      10             : #include <mrs_uav_managers/controller.h>
+      11             : #include <mrs_uav_managers/tracker.h>
+      12             : 
+      13             : #include <mrs_msgs/String.h>
+      14             : #include <mrs_msgs/Float64Stamped.h>
+      15             : #include <mrs_msgs/ObstacleSectors.h>
+      16             : #include <mrs_msgs/BoolStamped.h>
+      17             : #include <mrs_msgs/BumperStatus.h>
+      18             : #include <mrs_msgs/ControlManagerDiagnostics.h>
+      19             : #include <mrs_msgs/DynamicsConstraints.h>
+      20             : #include <mrs_msgs/ControlError.h>
+      21             : #include <mrs_msgs/GetFloat64.h>
+      22             : #include <mrs_msgs/ValidateReference.h>
+      23             : #include <mrs_msgs/ValidateReferenceList.h>
+      24             : #include <mrs_msgs/BumperParamsSrv.h>
+      25             : #include <mrs_msgs/TrackerCommand.h>
+      26             : #include <mrs_msgs/EstimatorInput.h>
+      27             : 
+      28             : #include <geometry_msgs/Point32.h>
+      29             : #include <geometry_msgs/TwistStamped.h>
+      30             : #include <geometry_msgs/PoseArray.h>
+      31             : #include <geometry_msgs/Vector3Stamped.h>
+      32             : 
+      33             : #include <nav_msgs/Odometry.h>
+      34             : 
+      35             : #include <sensor_msgs/Joy.h>
+      36             : #include <sensor_msgs/NavSatFix.h>
+      37             : 
+      38             : #include <mrs_lib/safety_zone/safety_zone.h>
+      39             : #include <mrs_lib/profiler.h>
+      40             : #include <mrs_lib/param_loader.h>
+      41             : #include <mrs_lib/utils.h>
+      42             : #include <mrs_lib/mutex.h>
+      43             : #include <mrs_lib/transformer.h>
+      44             : #include <mrs_lib/geometry/misc.h>
+      45             : #include <mrs_lib/geometry/cyclic.h>
+      46             : #include <mrs_lib/attitude_converter.h>
+      47             : #include <mrs_lib/subscribe_handler.h>
+      48             : #include <mrs_lib/msg_extractor.h>
+      49             : #include <mrs_lib/quadratic_throttle_model.h>
+      50             : #include <mrs_lib/publisher_handler.h>
+      51             : #include <mrs_lib/service_client_handler.h>
+      52             : 
+      53             : #include <mrs_msgs/HwApiCapabilities.h>
+      54             : #include <mrs_msgs/HwApiStatus.h>
+      55             : #include <mrs_msgs/HwApiRcChannels.h>
+      56             : 
+      57             : #include <mrs_msgs/HwApiActuatorCmd.h>
+      58             : #include <mrs_msgs/HwApiControlGroupCmd.h>
+      59             : #include <mrs_msgs/HwApiAttitudeRateCmd.h>
+      60             : #include <mrs_msgs/HwApiAttitudeCmd.h>
+      61             : #include <mrs_msgs/HwApiAccelerationHdgRateCmd.h>
+      62             : #include <mrs_msgs/HwApiAccelerationHdgCmd.h>
+      63             : #include <mrs_msgs/HwApiVelocityHdgRateCmd.h>
+      64             : #include <mrs_msgs/HwApiVelocityHdgCmd.h>
+      65             : #include <mrs_msgs/HwApiPositionCmd.h>
+      66             : 
+      67             : #include <std_msgs/Float64.h>
+      68             : 
+      69             : #include <future>
+      70             : 
+      71             : #include <pluginlib/class_loader.h>
+      72             : 
+      73             : #include <nodelet/loader.h>
+      74             : 
+      75             : #include <eigen3/Eigen/Eigen>
+      76             : 
+      77             : #include <visualization_msgs/Marker.h>
+      78             : #include <visualization_msgs/MarkerArray.h>
+      79             : 
+      80             : #include <mrs_msgs/Reference.h>
+      81             : #include <mrs_msgs/ReferenceStamped.h>
+      82             : #include <mrs_msgs/ReferenceList.h>
+      83             : #include <mrs_msgs/TrajectoryReference.h>
+      84             : 
+      85             : #include <mrs_msgs/ReferenceStampedSrv.h>
+      86             : #include <mrs_msgs/ReferenceStampedSrvRequest.h>
+      87             : #include <mrs_msgs/ReferenceStampedSrvResponse.h>
+      88             : 
+      89             : #include <mrs_msgs/VelocityReferenceStampedSrv.h>
+      90             : #include <mrs_msgs/VelocityReferenceStampedSrvRequest.h>
+      91             : #include <mrs_msgs/VelocityReferenceStampedSrvResponse.h>
+      92             : 
+      93             : #include <mrs_msgs/TransformReferenceSrv.h>
+      94             : #include <mrs_msgs/TransformReferenceSrvRequest.h>
+      95             : #include <mrs_msgs/TransformReferenceSrvResponse.h>
+      96             : 
+      97             : #include <mrs_msgs/TransformPoseSrv.h>
+      98             : #include <mrs_msgs/TransformPoseSrvRequest.h>
+      99             : #include <mrs_msgs/TransformPoseSrvResponse.h>
+     100             : 
+     101             : #include <mrs_msgs/TransformVector3Srv.h>
+     102             : #include <mrs_msgs/TransformVector3SrvRequest.h>
+     103             : #include <mrs_msgs/TransformVector3SrvResponse.h>
+     104             : 
+     105             : #include <mrs_msgs/Float64StampedSrv.h>
+     106             : #include <mrs_msgs/Float64StampedSrvRequest.h>
+     107             : #include <mrs_msgs/Float64StampedSrvResponse.h>
+     108             : 
+     109             : #include <mrs_msgs/Vec4.h>
+     110             : #include <mrs_msgs/Vec4Request.h>
+     111             : #include <mrs_msgs/Vec4Response.h>
+     112             : 
+     113             : #include <mrs_msgs/Vec1.h>
+     114             : #include <mrs_msgs/Vec1Request.h>
+     115             : #include <mrs_msgs/Vec1Response.h>
+     116             : 
+     117             : //}
+     118             : 
+     119             : /* defines //{ */
+     120             : 
+     121             : #define TAU 2 * M_PI
+     122             : #define REF_X 0
+     123             : #define REF_Y 1
+     124             : #define REF_Z 2
+     125             : #define REF_HEADING 3
+     126             : #define ELAND_STR "eland"
+     127             : #define EHOVER_STR "ehover"
+     128             : #define ESCALATING_FAILSAFE_STR "escalating_failsafe"
+     129             : #define FAILSAFE_STR "failsafe"
+     130             : #define INPUT_UAV_STATE 0
+     131             : #define INPUT_ODOMETRY 1
+     132             : #define RC_DEADBAND 0.2
+     133             : 
+     134             : //}
+     135             : 
+     136             : /* using //{ */
+     137             : 
+     138             : using vec2_t = mrs_lib::geometry::vec_t<2>;
+     139             : using vec3_t = mrs_lib::geometry::vec_t<3>;
+     140             : 
+     141             : using radians  = mrs_lib::geometry::radians;
+     142             : using sradians = mrs_lib::geometry::sradians;
+     143             : 
+     144             : //}
+     145             : 
+     146             : namespace mrs_uav_managers
+     147             : {
+     148             : 
+     149             : namespace control_manager
+     150             : {
+     151             : 
+     152             : /* //{ class ControlManager */
+     153             : 
+     154             : // state machine
+     155             : typedef enum
+     156             : {
+     157             : 
+     158             :   IDLE_STATE,
+     159             :   LANDING_STATE,
+     160             : 
+     161             : } LandingStates_t;
+     162             : 
+     163             : const char* state_names[2] = {
+     164             : 
+     165             :     "IDLING", "LANDING"};
+     166             : 
+     167             : // state machine
+     168             : typedef enum
+     169             : {
+     170             : 
+     171             :   FCU_FRAME,
+     172             :   RELATIVE_FRAME,
+     173             :   ABSOLUTE_FRAME
+     174             : 
+     175             : } ReferenceFrameType_t;
+     176             : 
+     177             : // state machine
+     178             : typedef enum
+     179             : {
+     180             : 
+     181             :   ESC_NONE_STATE     = 0,
+     182             :   ESC_EHOVER_STATE   = 1,
+     183             :   ESC_ELAND_STATE    = 2,
+     184             :   ESC_FAILSAFE_STATE = 3,
+     185             :   ESC_FINISHED_STATE = 4,
+     186             : 
+     187             : } EscalatingFailsafeStates_t;
+     188             : 
+     189             : /* class ControllerParams() //{ */
+     190             : 
+     191             : class ControllerParams {
+     192             : 
+     193             : public:
+     194             :   ControllerParams(std::string address, std::string name_space, double eland_threshold, double failsafe_threshold, double odometry_innovation_threshold,
+     195             :                    bool human_switchable);
+     196             : 
+     197             : public:
+     198             :   double      failsafe_threshold;
+     199             :   double      eland_threshold;
+     200             :   double      odometry_innovation_threshold;
+     201             :   std::string address;
+     202             :   std::string name_space;
+     203             :   bool        human_switchable;
+     204             : };
+     205             : 
+     206          35 : ControllerParams::ControllerParams(std::string address, std::string name_space, double eland_threshold, double failsafe_threshold,
+     207          35 :                                    double odometry_innovation_threshold, bool human_switchable) {
+     208             : 
+     209          35 :   this->eland_threshold               = eland_threshold;
+     210          35 :   this->odometry_innovation_threshold = odometry_innovation_threshold;
+     211          35 :   this->failsafe_threshold            = failsafe_threshold;
+     212          35 :   this->address                       = address;
+     213          35 :   this->name_space                    = name_space;
+     214          35 :   this->human_switchable              = human_switchable;
+     215          35 : }
+     216             : 
+     217             : //}
+     218             : 
+     219             : /* class TrackerParams() //{ */
+     220             : 
+     221             : class TrackerParams {
+     222             : 
+     223             : public:
+     224             :   TrackerParams(std::string address, std::string name_space, bool human_switchable);
+     225             : 
+     226             : public:
+     227             :   std::string address;
+     228             :   std::string name_space;
+     229             :   bool        human_switchable;
+     230             : };
+     231             : 
+     232          42 : TrackerParams::TrackerParams(std::string address, std::string name_space, bool human_switchable) {
+     233             : 
+     234          42 :   this->address          = address;
+     235          42 :   this->name_space       = name_space;
+     236          42 :   this->human_switchable = human_switchable;
+     237          42 : }
+     238             : 
+     239             : //}
+     240             : 
+     241             : class ControlManager : public nodelet::Nodelet {
+     242             : 
+     243             : public:
+     244             :   virtual void onInit();
+     245             : 
+     246             : private:
+     247             :   ros::NodeHandle   nh_;
+     248             :   std::atomic<bool> is_initialized_ = false;
+     249             :   std::string       _uav_name_;
+     250             :   std::string       _body_frame_;
+     251             : 
+     252             :   std::string _custom_config_;
+     253             :   std::string _platform_config_;
+     254             :   std::string _world_config_;
+     255             :   std::string _network_config_;
+     256             : 
+     257             :   // | --------------- dynamic loading of trackers -------------- |
+     258             : 
+     259             :   std::unique_ptr<pluginlib::ClassLoader<mrs_uav_managers::Tracker>> tracker_loader_;  // pluginlib loader of dynamically loaded trackers
+     260             :   std::vector<std::string>                                           _tracker_names_;  // list of tracker names
+     261             :   std::map<std::string, TrackerParams>                               trackers_;        // map between tracker names and tracker param
+     262             :   std::vector<boost::shared_ptr<mrs_uav_managers::Tracker>>          tracker_list_;    // list of trackers, routines are callable from this
+     263             :   std::mutex                                                         mutex_tracker_list_;
+     264             : 
+     265             :   // | ------------- dynamic loading of controllers ------------- |
+     266             : 
+     267             :   std::unique_ptr<pluginlib::ClassLoader<mrs_uav_managers::Controller>> controller_loader_;  // pluginlib loader of dynamically loaded controllers
+     268             :   std::vector<std::string>                                              _controller_names_;  // list of controller names
+     269             :   std::map<std::string, ControllerParams>                               controllers_;        // map between controller names and controller params
+     270             :   std::vector<boost::shared_ptr<mrs_uav_managers::Controller>>          controller_list_;    // list of controllers, routines are callable from this
+     271             :   std::mutex                                                            mutex_controller_list_;
+     272             : 
+     273             :   // | ------------------------- HW API ------------------------- |
+     274             : 
+     275             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiCapabilities> sh_hw_api_capabilities_;
+     276             : 
+     277             :   OutputPublisher control_output_publisher_;
+     278             : 
+     279             :   ControlOutputModalities_t _hw_api_inputs_;
+     280             : 
+     281             :   double desired_uav_state_rate_ = 100.0;
+     282             : 
+     283             :   // this timer will check till we already got the hardware api diagnostics
+     284             :   // then it will trigger the initialization of the controllers and finish
+     285             :   // the initialization of the ControlManager
+     286             :   ros::Timer timer_hw_api_capabilities_;
+     287             :   void       timerHwApiCapabilities(const ros::TimerEvent& event);
+     288             : 
+     289             :   void preinitialize(void);
+     290             :   void initialize(void);
+     291             : 
+     292             :   // | ------------ tracker and controller switching ------------ |
+     293             : 
+     294             :   std::tuple<bool, std::string> switchController(const std::string& controller_name);
+     295             :   std::tuple<bool, std::string> switchTracker(const std::string& tracker_name);
+     296             : 
+     297             :   // the time of last switching of a tracker or a controller
+     298             :   ros::Time  controller_tracker_switch_time_;
+     299             :   std::mutex mutex_controller_tracker_switch_time_;
+     300             : 
+     301             :   // | -------------------- the transformer  -------------------- |
+     302             : 
+     303             :   std::shared_ptr<mrs_lib::Transformer> transformer_;
+     304             : 
+     305             :   // | ------------------- scope timer logger ------------------- |
+     306             : 
+     307             :   bool                                       scope_timer_enabled_ = false;
+     308             :   std::shared_ptr<mrs_lib::ScopeTimerLogger> scope_timer_logger_;
+     309             : 
+     310             :   // | --------------------- general params --------------------- |
+     311             : 
+     312             :   // defines the type of state input: odometry or uav_state mesasge types
+     313             :   int _state_input_;
+     314             : 
+     315             :   // names of important trackers
+     316             :   std::string _null_tracker_name_;     // null tracker is active when UAV is not in the air
+     317             :   std::string _ehover_tracker_name_;   // ehover tracker is used for emergency hovering
+     318             :   std::string _landoff_tracker_name_;  // landoff is used for landing and takeoff
+     319             : 
+     320             :   // names of important controllers
+     321             :   std::string _failsafe_controller_name_;  // controller used for feed-forward failsafe
+     322             :   std::string _eland_controller_name_;     // controller used for emergancy landing
+     323             : 
+     324             :   // joystick control
+     325             :   bool        _joystick_enabled_ = false;
+     326             :   int         _joystick_mode_;
+     327             :   std::string _joystick_tracker_name_;
+     328             :   std::string _joystick_controller_name_;
+     329             :   std::string _joystick_fallback_tracker_name_;
+     330             :   std::string _joystick_fallback_controller_name_;
+     331             : 
+     332             :   // should disarm after emergancy landing?
+     333             :   bool _eland_disarm_enabled_ = false;
+     334             : 
+     335             :   // enabling the emergency handoff -> will disable eland and failsafe
+     336             :   bool _rc_emergency_handoff_ = false;
+     337             : 
+     338             :   // what throttle should be output when null tracker is active?
+     339             :   double _min_throttle_null_tracker_ = 0.0;
+     340             : 
+     341             :   // rates of all the timers
+     342             :   double _status_timer_rate_   = 0;
+     343             :   double _safety_timer_rate_   = 0;
+     344             :   double _elanding_timer_rate_ = 0;
+     345             :   double _failsafe_timer_rate_ = 0;
+     346             :   double _bumper_timer_rate_   = 0;
+     347             : 
+     348             :   bool _snap_trajectory_to_safety_area_ = false;
+     349             : 
+     350             :   // | -------------- uav_state/odometry subscriber ------------- |
+     351             : 
+     352             :   mrs_lib::SubscribeHandler<nav_msgs::Odometry> sh_odometry_;
+     353             :   mrs_lib::SubscribeHandler<mrs_msgs::UavState> sh_uav_state_;
+     354             : 
+     355             :   mrs_msgs::UavState uav_state_;
+     356             :   mrs_msgs::UavState previous_uav_state_;
+     357             :   bool               got_uav_state_               = false;
+     358             :   double             _uav_state_max_missing_time_ = 0;  // how long should we tolerate missing state estimate?
+     359             :   double             uav_roll_                    = 0;
+     360             :   double             uav_pitch_                   = 0;
+     361             :   double             uav_yaw_                     = 0;
+     362             :   double             uav_heading_                 = 0;
+     363             :   std::mutex         mutex_uav_state_;
+     364             : 
+     365             :   // odometry hiccup detection
+     366             :   double uav_state_avg_dt_        = 1;
+     367             :   double uav_state_hiccup_factor_ = 1;
+     368             :   int    uav_state_count_         = 0;
+     369             : 
+     370             :   mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix> sh_gnss_;
+     371             : 
+     372             :   // | -------------- safety area max z subscriber -------------- |
+     373             : 
+     374             :   mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped> sh_max_z_;
+     375             : 
+     376             :   // | ------------- odometry innovation subscriber ------------- |
+     377             : 
+     378             :   // odometry innovation is published by the odometry node
+     379             :   // it is used to issue eland if the estimator's input is too wonky
+     380             :   mrs_lib::SubscribeHandler<nav_msgs::Odometry> sh_odometry_innovation_;
+     381             : 
+     382             :   // | --------------------- common handlers -------------------- |
+     383             : 
+     384             :   // contains handlers that are shared with trackers and controllers
+     385             :   std::shared_ptr<mrs_uav_managers::control_manager::CommonHandlers_t> common_handlers_;
+     386             : 
+     387             :   // | --------------- tracker and controller IDs --------------- |
+     388             : 
+     389             :   // keeping track of currently active controllers and trackers
+     390             :   unsigned int active_tracker_idx_    = 0;
+     391             :   unsigned int active_controller_idx_ = 0;
+     392             : 
+     393             :   // indeces of some notable trackers
+     394             :   unsigned int _ehover_tracker_idx_               = 0;
+     395             :   unsigned int _landoff_tracker_idx_              = 0;
+     396             :   unsigned int _joystick_tracker_idx_             = 0;
+     397             :   unsigned int _joystick_controller_idx_          = 0;
+     398             :   unsigned int _failsafe_controller_idx_          = 0;
+     399             :   unsigned int _joystick_fallback_controller_idx_ = 0;
+     400             :   unsigned int _joystick_fallback_tracker_idx_    = 0;
+     401             :   unsigned int _null_tracker_idx_                 = 0;
+     402             :   unsigned int _eland_controller_idx_             = 0;
+     403             : 
+     404             :   // | -------------- enabling the output publisher ------------- |
+     405             : 
+     406             :   void              toggleOutput(const bool& input);
+     407             :   std::atomic<bool> output_enabled_ = false;
+     408             : 
+     409             :   // | ----------------------- publishers ----------------------- |
+     410             : 
+     411             :   mrs_lib::PublisherHandler<mrs_msgs::ControllerDiagnostics>     ph_controller_diagnostics_;
+     412             :   mrs_lib::PublisherHandler<mrs_msgs::TrackerCommand>            ph_tracker_cmd_;
+     413             :   mrs_lib::PublisherHandler<mrs_msgs::EstimatorInput>            ph_mrs_odom_input_;
+     414             :   mrs_lib::PublisherHandler<nav_msgs::Odometry>                  ph_control_reference_odom_;
+     415             :   mrs_lib::PublisherHandler<mrs_msgs::ControlManagerDiagnostics> ph_diagnostics_;
+     416             :   mrs_lib::PublisherHandler<std_msgs::Empty>                     ph_offboard_on_;
+     417             :   mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>            ph_tilt_error_;
+     418             :   mrs_lib::PublisherHandler<std_msgs::Float64>                   ph_mass_estimate_;
+     419             :   mrs_lib::PublisherHandler<std_msgs::Float64>                   ph_throttle_;
+     420             :   mrs_lib::PublisherHandler<std_msgs::Float64>                   ph_thrust_;
+     421             :   mrs_lib::PublisherHandler<mrs_msgs::ControlError>              ph_control_error_;
+     422             :   mrs_lib::PublisherHandler<visualization_msgs::MarkerArray>     ph_safety_area_markers_;
+     423             :   mrs_lib::PublisherHandler<visualization_msgs::MarkerArray>     ph_safety_area_coordinates_markers_;
+     424             :   mrs_lib::PublisherHandler<visualization_msgs::MarkerArray>     ph_disturbances_markers_;
+     425             :   mrs_lib::PublisherHandler<mrs_msgs::BumperStatus>              ph_bumper_status_;
+     426             :   mrs_lib::PublisherHandler<mrs_msgs::DynamicsConstraints>       ph_current_constraints_;
+     427             :   mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>            ph_heading_;
+     428             :   mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>            ph_speed_;
+     429             : 
+     430             :   // | --------------------- service servers -------------------- |
+     431             : 
+     432             :   ros::ServiceServer service_server_switch_tracker_;
+     433             :   ros::ServiceServer service_server_switch_controller_;
+     434             :   ros::ServiceServer service_server_reset_tracker_;
+     435             :   ros::ServiceServer service_server_hover_;
+     436             :   ros::ServiceServer service_server_ehover_;
+     437             :   ros::ServiceServer service_server_failsafe_;
+     438             :   ros::ServiceServer service_server_failsafe_escalating_;
+     439             :   ros::ServiceServer service_server_toggle_output_;
+     440             :   ros::ServiceServer service_server_arm_;
+     441             :   ros::ServiceServer service_server_enable_callbacks_;
+     442             :   ros::ServiceServer service_server_set_constraints_;
+     443             :   ros::ServiceServer service_server_use_joystick_;
+     444             :   ros::ServiceServer service_server_use_safety_area_;
+     445             :   ros::ServiceServer service_server_emergency_reference_;
+     446             :   ros::ServiceServer service_server_pirouette_;
+     447             :   ros::ServiceServer service_server_eland_;
+     448             :   ros::ServiceServer service_server_parachute_;
+     449             : 
+     450             :   // human callbable services for references
+     451             :   ros::ServiceServer service_server_goto_;
+     452             :   ros::ServiceServer service_server_goto_fcu_;
+     453             :   ros::ServiceServer service_server_goto_relative_;
+     454             :   ros::ServiceServer service_server_goto_altitude_;
+     455             :   ros::ServiceServer service_server_set_heading_;
+     456             :   ros::ServiceServer service_server_set_heading_relative_;
+     457             : 
+     458             :   // the reference service and subscriber
+     459             :   ros::ServiceServer                                    service_server_reference_;
+     460             :   mrs_lib::SubscribeHandler<mrs_msgs::ReferenceStamped> sh_reference_;
+     461             : 
+     462             :   // the velocity reference service and subscriber
+     463             :   ros::ServiceServer                                            service_server_velocity_reference_;
+     464             :   mrs_lib::SubscribeHandler<mrs_msgs::VelocityReferenceStamped> sh_velocity_reference_;
+     465             : 
+     466             :   // trajectory tracking
+     467             :   ros::ServiceServer                                       service_server_trajectory_reference_;
+     468             :   mrs_lib::SubscribeHandler<mrs_msgs::TrajectoryReference> sh_trajectory_reference_;
+     469             :   ros::ServiceServer                                       service_server_start_trajectory_tracking_;
+     470             :   ros::ServiceServer                                       service_server_stop_trajectory_tracking_;
+     471             :   ros::ServiceServer                                       service_server_resume_trajectory_tracking_;
+     472             :   ros::ServiceServer                                       service_server_goto_trajectory_start_;
+     473             : 
+     474             :   // transform service servers
+     475             :   ros::ServiceServer service_server_transform_reference_;
+     476             :   ros::ServiceServer service_server_transform_pose_;
+     477             :   ros::ServiceServer service_server_transform_vector3_;
+     478             : 
+     479             :   // safety area services
+     480             :   ros::ServiceServer service_server_validate_reference_;
+     481             :   ros::ServiceServer service_server_validate_reference_2d_;
+     482             :   ros::ServiceServer service_server_validate_reference_list_;
+     483             : 
+     484             :   // bumper service servers
+     485             :   ros::ServiceServer service_server_bumper_enabler_;
+     486             :   ros::ServiceServer service_server_bumper_repulsion_enabler_;
+     487             : 
+     488             :   // service clients
+     489             :   mrs_lib::ServiceClientHandler<std_srvs::SetBool> sch_arming_;
+     490             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger> sch_eland_;
+     491             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger> sch_shutdown_;
+     492             :   mrs_lib::ServiceClientHandler<std_srvs::SetBool> sch_set_odometry_callbacks_;
+     493             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger> sch_parachute_;
+     494             : 
+     495             :   // safety area min z servers
+     496             :   ros::ServiceServer service_server_set_min_z_;
+     497             :   ros::ServiceServer service_server_get_min_z_;
+     498             : 
+     499             :   // | --------- trackers' and controllers' last results -------- |
+     500             : 
+     501             :   // the last result of an active tracker
+     502             :   std::optional<mrs_msgs::TrackerCommand> last_tracker_cmd_;
+     503             :   std::mutex                              mutex_last_tracker_cmd_;
+     504             : 
+     505             :   // the last result of an active controller
+     506             :   Controller::ControlOutput last_control_output_;
+     507             :   std::mutex                mutex_last_control_output_;
+     508             : 
+     509             :   // | -------------- HW API diagnostics subscriber ------------- |
+     510             : 
+     511             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiStatus> sh_hw_api_status_;
+     512             : 
+     513             :   bool offboard_mode_          = false;
+     514             :   bool offboard_mode_was_true_ = false;  // if it was ever true
+     515             :   bool armed_                  = false;
+     516             : 
+     517             :   // | -------------------- throttle and mass ------------------- |
+     518             : 
+     519             :   // throttle mass estimation during eland
+     520             :   double    throttle_mass_estimate_   = 0;
+     521             :   bool      throttle_under_threshold_ = false;
+     522             :   ros::Time throttle_mass_estimate_first_time_;
+     523             : 
+     524             :   // | ---------------------- safety params --------------------- |
+     525             : 
+     526             :   // failsafe when tilt error is too large
+     527             :   bool   _tilt_error_disarm_enabled_;
+     528             :   double _tilt_error_disarm_timeout_;
+     529             :   double _tilt_error_disarm_threshold_;
+     530             : 
+     531             :   ros::Time tilt_error_disarm_time_;
+     532             :   bool      tilt_error_disarm_over_thr_ = false;
+     533             : 
+     534             :   // elanding when tilt error is too large
+     535             :   bool   _tilt_limit_eland_enabled_;
+     536             :   double _tilt_limit_eland_ = 0;  // [rad]
+     537             : 
+     538             :   // disarming when tilt error is too large
+     539             :   bool   _tilt_limit_disarm_enabled_;
+     540             :   double _tilt_limit_disarm_ = 0;  // [rad]
+     541             : 
+     542             :   // elanding when yaw error is too large
+     543             :   bool   _yaw_error_eland_enabled_;
+     544             :   double _yaw_error_eland_ = 0;  // [rad]
+     545             : 
+     546             :   // keeping track of control errors
+     547             :   std::optional<double> tilt_error_ = 0;
+     548             :   std::optional<double> yaw_error_  = 0;
+     549             :   std::mutex            mutex_attitude_error_;
+     550             : 
+     551             :   std::optional<Eigen::Vector3d> position_error_;
+     552             :   std::mutex                     mutex_position_error_;
+     553             : 
+     554             :   // control error for triggering failsafe, eland, etc.
+     555             :   // this filled with the current controllers failsafe threshold
+     556             :   double _failsafe_threshold_                = 0;  // control error for triggering failsafe
+     557             :   double _eland_threshold_                   = 0;  // control error for triggering eland
+     558             :   bool   _odometry_innovation_check_enabled_ = false;
+     559             :   double _odometry_innovation_threshold_     = 0;  // innovation size for triggering eland
+     560             : 
+     561             :   bool callbacks_enabled_ = true;
+     562             : 
+     563             :   // | ------------------------ parachute ----------------------- |
+     564             : 
+     565             :   bool _parachute_enabled_ = false;
+     566             : 
+     567             :   std::tuple<bool, std::string> deployParachute(void);
+     568             :   bool                          parachuteSrv(void);
+     569             : 
+     570             :   // | ----------------------- safety area ---------------------- |
+     571             : 
+     572             :   // safety area
+     573             :   std::unique_ptr<mrs_lib::SafetyZone> safety_zone_;
+     574             : 
+     575             :   std::atomic<bool> use_safety_area_ = false;
+     576             : 
+     577             :   std::string _safety_area_horizontal_frame_;
+     578             :   std::string _safety_area_vertical_frame_;
+     579             : 
+     580             :   double _safety_area_min_z_ = 0;
+     581             :   double _safety_area_max_z_ = 0;
+     582             : 
+     583             :   // safety area routines
+     584             :   // those are passed to trackers using the common_handlers object
+     585             :   bool   isPointInSafetyArea2d(const mrs_msgs::ReferenceStamped& point);
+     586             :   bool   isPointInSafetyArea3d(const mrs_msgs::ReferenceStamped& point);
+     587             :   bool   isPathToPointInSafetyArea2d(const mrs_msgs::ReferenceStamped& from, const mrs_msgs::ReferenceStamped& to);
+     588             :   bool   isPathToPointInSafetyArea3d(const mrs_msgs::ReferenceStamped& from, const mrs_msgs::ReferenceStamped& to);
+     589             :   double getMinZ(const std::string& frame_id);
+     590             :   double getMaxZ(const std::string& frame_id);
+     591             : 
+     592             :   // | ------------------------ callbacks ----------------------- |
+     593             : 
+     594             :   // topic callbacks
+     595             :   void callbackOdometry(const nav_msgs::Odometry::ConstPtr msg);
+     596             :   void callbackUavState(const mrs_msgs::UavState::ConstPtr msg);
+     597             :   void callbackHwApiStatus(const mrs_msgs::HwApiStatus::ConstPtr msg);
+     598             :   void callbackGNSS(const sensor_msgs::NavSatFix::ConstPtr msg);
+     599             :   void callbackRC(const mrs_msgs::HwApiRcChannels::ConstPtr msg);
+     600             : 
+     601             :   // topic timeouts
+     602             :   void timeoutUavState(const double& missing_for);
+     603             : 
+     604             :   // switching controller and tracker services
+     605             :   bool callbackSwitchTracker(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res);
+     606             :   bool callbackSwitchController(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res);
+     607             :   bool callbackTrackerResetStatic(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     608             : 
+     609             :   // reference callbacks
+     610             :   void callbackReferenceTopic(const mrs_msgs::ReferenceStamped::ConstPtr msg);
+     611             :   void callbackVelocityReferenceTopic(const mrs_msgs::VelocityReferenceStamped::ConstPtr msg);
+     612             :   void callbackTrajectoryReferenceTopic(const mrs_msgs::TrajectoryReference::ConstPtr msg);
+     613             :   bool callbackGoto(mrs_msgs::Vec4::Request& req, mrs_msgs::Vec4::Response& res);
+     614             :   bool callbackGotoFcu(mrs_msgs::Vec4::Request& req, mrs_msgs::Vec4::Response& res);
+     615             :   bool callbackGotoRelative(mrs_msgs::Vec4::Request& req, mrs_msgs::Vec4::Response& res);
+     616             :   bool callbackGotoAltitude(mrs_msgs::Vec1::Request& req, mrs_msgs::Vec1::Response& res);
+     617             :   bool callbackSetHeading(mrs_msgs::Vec1::Request& req, mrs_msgs::Vec1::Response& res);
+     618             :   bool callbackSetHeadingRelative(mrs_msgs::Vec1::Request& req, mrs_msgs::Vec1::Response& res);
+     619             :   bool callbackReferenceService(mrs_msgs::ReferenceStampedSrv::Request& req, mrs_msgs::ReferenceStampedSrv::Response& res);
+     620             :   bool callbackVelocityReferenceService(mrs_msgs::VelocityReferenceStampedSrv::Request& req, mrs_msgs::VelocityReferenceStampedSrv::Response& res);
+     621             :   bool callbackTrajectoryReferenceService(mrs_msgs::TrajectoryReferenceSrv::Request& req, mrs_msgs::TrajectoryReferenceSrv::Response& res);
+     622             :   bool callbackEmergencyReference(mrs_msgs::ReferenceStampedSrv::Request& req, mrs_msgs::ReferenceStampedSrv::Response& res);
+     623             : 
+     624             :   // safety callbacks
+     625             :   bool callbackHover(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     626             :   bool callbackStartTrajectoryTracking([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     627             :   bool callbackStopTrajectoryTracking([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     628             :   bool callbackResumeTrajectoryTracking([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     629             :   bool callbackGotoTrajectoryStart([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     630             :   bool callbackEHover(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     631             :   bool callbackFailsafe(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     632             :   bool callbackFailsafeEscalating(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     633             :   bool callbackEland(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     634             :   bool callbackParachute([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     635             :   bool callbackToggleOutput(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res);
+     636             :   bool callbackArm(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res);
+     637             :   bool callbackEnableCallbacks(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res);
+     638             :   bool callbackEnableBumper(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res);
+     639             :   bool callbackUseSafetyArea(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res);
+     640             :   bool callbackBumperSetParams(mrs_msgs::BumperParamsSrv::Request& req, mrs_msgs::BumperParamsSrv::Response& res);
+     641             : 
+     642             :   bool callbackGetMinZ(mrs_msgs::GetFloat64::Request& req, mrs_msgs::GetFloat64::Response& res);
+     643             : 
+     644             :   bool callbackValidateReference(mrs_msgs::ValidateReference::Request& req, mrs_msgs::ValidateReference::Response& res);
+     645             :   bool callbackValidateReference2d(mrs_msgs::ValidateReference::Request& req, mrs_msgs::ValidateReference::Response& res);
+     646             :   bool callbackValidateReferenceList(mrs_msgs::ValidateReferenceList::Request& req, mrs_msgs::ValidateReferenceList::Response& res);
+     647             : 
+     648             :   // transformation callbacks
+     649             :   bool callbackTransformReference(mrs_msgs::TransformReferenceSrv::Request& req, mrs_msgs::TransformReferenceSrv::Response& res);
+     650             :   bool callbackTransformPose(mrs_msgs::TransformPoseSrv::Request& req, mrs_msgs::TransformPoseSrv::Response& res);
+     651             :   bool callbackTransformVector3(mrs_msgs::TransformVector3Srv::Request& req, mrs_msgs::TransformVector3Srv::Response& res);
+     652             : 
+     653             :   // | ----------------------- constraints ---------------------- |
+     654             : 
+     655             :   // sets constraints to all trackers
+     656             :   bool callbackSetConstraints(mrs_msgs::DynamicsConstraintsSrv::Request& req, mrs_msgs::DynamicsConstraintsSrv::Response& res);
+     657             : 
+     658             :   // constraints management
+     659             :   bool              got_constraints_ = false;
+     660             :   std::mutex        mutex_constraints_;
+     661             :   void              setConstraints(const mrs_msgs::DynamicsConstraintsSrvRequest& constraints);
+     662             :   void              setConstraintsToTrackers(const mrs_msgs::DynamicsConstraintsSrvRequest& constraints);
+     663             :   void              setConstraintsToControllers(const mrs_msgs::DynamicsConstraintsSrvRequest& constraints);
+     664             :   std::atomic<bool> constraints_being_enforced_ = false;
+     665             : 
+     666             :   std::optional<mrs_msgs::DynamicsConstraintsSrvRequest> enforceControllersConstraints(const mrs_msgs::DynamicsConstraintsSrvRequest& constraints);
+     667             : 
+     668             :   mrs_msgs::DynamicsConstraintsSrvRequest current_constraints_;
+     669             :   mrs_msgs::DynamicsConstraintsSrvRequest sanitized_constraints_;
+     670             : 
+     671             :   // | ------------------ emergency triggered? ------------------ |
+     672             : 
+     673             :   bool failsafe_triggered_ = false;
+     674             :   bool eland_triggered_    = false;
+     675             : 
+     676             :   // | ------------------------- timers ------------------------- |
+     677             : 
+     678             :   // timer for regular status publishing
+     679             :   ros::Timer timer_status_;
+     680             :   void       timerStatus(const ros::TimerEvent& event);
+     681             : 
+     682             :   // timer for issuing the failsafe landing
+     683             :   ros::Timer timer_failsafe_;
+     684             :   void       timerFailsafe(const ros::TimerEvent& event);
+     685             : 
+     686             :   // oneshot timer for running controllers and trackers
+     687             :   void              asyncControl(void);
+     688             :   std::atomic<bool> running_async_control_ = false;
+     689             :   std::future<void> async_control_result_;
+     690             : 
+     691             :   // timer for issuing emergancy landing
+     692             :   ros::Timer timer_eland_;
+     693             :   void       timerEland(const ros::TimerEvent& event);
+     694             : 
+     695             :   // timer for regular checking of controller errors
+     696             :   ros::Timer        timer_safety_;
+     697             :   void              timerSafety(const ros::TimerEvent& event);
+     698             :   std::atomic<bool> running_safety_timer_        = false;
+     699             :   std::atomic<bool> odometry_switch_in_progress_ = false;
+     700             : 
+     701             :   // timer for issuing the pirouette
+     702             :   ros::Timer timer_pirouette_;
+     703             :   void       timerPirouette(const ros::TimerEvent& event);
+     704             : 
+     705             :   // | --------------------- obstacle bumper -------------------- |
+     706             : 
+     707             :   // bumper timer
+     708             :   ros::Timer timer_bumper_;
+     709             :   void       timerBumper(const ros::TimerEvent& event);
+     710             : 
+     711             :   // bumper subscriber
+     712             :   mrs_lib::SubscribeHandler<mrs_msgs::ObstacleSectors> sh_bumper_;
+     713             : 
+     714             :   bool        _bumper_switch_tracker_    = false;
+     715             :   bool        _bumper_switch_controller_ = false;
+     716             :   std::string _bumper_tracker_name_;
+     717             :   std::string _bumper_controller_name_;
+     718             :   std::string bumper_previous_tracker_;
+     719             :   std::string bumper_previous_controller_;
+     720             : 
+     721             :   std::atomic<bool> bumper_enabled_ = false;
+     722             :   std::atomic<bool> repulsing_      = false;
+     723             : 
+     724             :   double _bumper_horizontal_distance_ = 0;
+     725             :   double _bumper_vertical_distance_   = 0;
+     726             : 
+     727             :   double _bumper_horizontal_overshoot_ = 0;
+     728             :   double _bumper_vertical_overshoot_   = 0;
+     729             : 
+     730             :   int  bumperGetSectorId(const double& x, const double& y, const double& z);
+     731             :   bool bumperPushFromObstacle(void);
+     732             : 
+     733             :   // | --------------- safety checks and failsafes -------------- |
+     734             : 
+     735             :   // escalating failsafe (eland -> failsafe -> disarm)
+     736             :   bool                       _service_escalating_failsafe_enabled_ = false;
+     737             :   bool                       _rc_escalating_failsafe_enabled_      = false;
+     738             :   double                     _escalating_failsafe_timeout_         = 0;
+     739             :   ros::Time                  escalating_failsafe_time_;
+     740             :   bool                       _escalating_failsafe_ehover_   = false;
+     741             :   bool                       _escalating_failsafe_eland_    = false;
+     742             :   bool                       _escalating_failsafe_failsafe_ = false;
+     743             :   double                     _rc_escalating_failsafe_threshold_;
+     744             :   int                        _rc_escalating_failsafe_channel_  = 0;
+     745             :   bool                       rc_escalating_failsafe_triggered_ = false;
+     746             :   EscalatingFailsafeStates_t state_escalating_failsafe_        = ESC_NONE_STATE;
+     747             : 
+     748             :   std::string _tracker_error_action_;
+     749             : 
+     750             :   // emergancy landing state machine
+     751             :   LandingStates_t current_state_landing_  = IDLE_STATE;
+     752             :   LandingStates_t previous_state_landing_ = IDLE_STATE;
+     753             :   std::mutex      mutex_landing_state_machine_;
+     754             :   void            changeLandingState(LandingStates_t new_state);
+     755             :   double          _uav_mass_ = 0;
+     756             :   double          _elanding_cutoff_mass_factor_;
+     757             :   double          _elanding_cutoff_timeout_;
+     758             :   double          landing_uav_mass_ = 0;
+     759             : 
+     760             :   // initial body disturbance loaded from params
+     761             :   double _initial_body_disturbance_x_ = 0;
+     762             :   double _initial_body_disturbance_y_ = 0;
+     763             : 
+     764             :   // profiling
+     765             :   mrs_lib::Profiler profiler_;
+     766             :   bool              _profiler_enabled_ = false;
+     767             : 
+     768             :   // automatic pc shutdown (DARPA specific)
+     769             :   bool _automatic_pc_shutdown_enabled_ = false;
+     770             : 
+     771             :   // diagnostics publishing
+     772             :   void       publishDiagnostics(void);
+     773             :   std::mutex mutex_diagnostics_;
+     774             : 
+     775             :   void                                             ungripSrv(void);
+     776             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger> sch_ungrip_;
+     777             : 
+     778             :   bool isFlyingNormally(void);
+     779             : 
+     780             :   // | ------------------------ pirouette ----------------------- |
+     781             : 
+     782             :   bool       _pirouette_enabled_ = false;
+     783             :   double     _pirouette_speed_;
+     784             :   double     _pirouette_timer_rate_;
+     785             :   std::mutex mutex_pirouette_;
+     786             :   double     pirouette_initial_heading_;
+     787             :   double     pirouette_iterator_;
+     788             :   bool       callbackPirouette(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     789             : 
+     790             :   // | -------------------- joystick control -------------------- |
+     791             : 
+     792             :   mrs_lib::SubscribeHandler<sensor_msgs::Joy> sh_joystick_;
+     793             : 
+     794             :   void callbackJoystick(const sensor_msgs::Joy::ConstPtr msg);
+     795             :   bool callbackUseJoystick([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     796             : 
+     797             :   // joystick buttons mappings
+     798             :   int _channel_A_, _channel_B_, _channel_X_, _channel_Y_, _channel_start_, _channel_back_, _channel_LT_, _channel_RT_, _channel_L_joy_, _channel_R_joy_;
+     799             : 
+     800             :   // channel numbers and channel multipliers
+     801             :   int    _channel_pitch_, _channel_roll_, _channel_heading_, _channel_throttle_;
+     802             :   double _channel_mult_pitch_, _channel_mult_roll_, _channel_mult_heading_, _channel_mult_throttle_;
+     803             : 
+     804             :   ros::Timer timer_joystick_;
+     805             :   void       timerJoystick(const ros::TimerEvent& event);
+     806             :   double     _joystick_timer_rate_ = 0;
+     807             : 
+     808             :   double _joystick_carrot_distance_ = 0;
+     809             : 
+     810             :   ros::Time joystick_start_press_time_;
+     811             :   bool      joystick_start_pressed_ = false;
+     812             : 
+     813             :   ros::Time joystick_back_press_time_;
+     814             :   bool      joystick_back_pressed_ = false;
+     815             :   bool      joystick_goto_enabled_ = false;
+     816             : 
+     817             :   bool      joystick_failsafe_pressed_ = false;
+     818             :   ros::Time joystick_failsafe_press_time_;
+     819             : 
+     820             :   bool      joystick_eland_pressed_ = false;
+     821             :   ros::Time joystick_eland_press_time_;
+     822             : 
+     823             :   // | ------------------- RC joystick control ------------------ |
+     824             : 
+     825             :   // listening to the RC channels as told by pixhawk
+     826             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiRcChannels> sh_hw_api_rc_;
+     827             : 
+     828             :   // the RC channel mapping of the main 4 control signals
+     829             :   double _rc_channel_pitch_, _rc_channel_roll_, _rc_channel_heading_, _rc_channel_throttle_;
+     830             : 
+     831             :   bool              _rc_goto_enabled_               = false;
+     832             :   std::atomic<bool> rc_goto_active_                 = false;
+     833             :   double            rc_joystick_channel_last_value_ = 0.5;
+     834             :   bool              rc_joystick_channel_was_low_    = false;
+     835             :   int               _rc_joystick_channel_           = 0;
+     836             : 
+     837             :   double _rc_horizontal_speed_ = 0;
+     838             :   double _rc_vertical_speed_   = 0;
+     839             :   double _rc_heading_rate_     = 0;
+     840             : 
+     841             :   // | ------------------- trajectory loading ------------------- |
+     842             : 
+     843             :   mrs_lib::PublisherHandler<geometry_msgs::PoseArray>        pub_debug_original_trajectory_poses_;
+     844             :   mrs_lib::PublisherHandler<visualization_msgs::MarkerArray> pub_debug_original_trajectory_markers_;
+     845             : 
+     846             :   // | --------------------- other routines --------------------- |
+     847             : 
+     848             :   // this is called to update the trackers and to receive position control command from the active one
+     849             :   void updateTrackers(void);
+     850             : 
+     851             :   // this is called to update the controllers and to receive attitude control command from the active one
+     852             :   void updateControllers(const mrs_msgs::UavState& uav_state);
+     853             : 
+     854             :   // sets the reference to the active tracker
+     855             :   std::tuple<bool, std::string> setReference(const mrs_msgs::ReferenceStamped reference_in);
+     856             : 
+     857             :   // sets the velocity reference to the active tracker
+     858             :   std::tuple<bool, std::string> setVelocityReference(const mrs_msgs::VelocityReferenceStamped& reference_in);
+     859             : 
+     860             :   // sets the reference trajectory to the active tracker
+     861             :   std::tuple<bool, std::string, bool, std::vector<std::string>, std::vector<bool>, std::vector<std::string>> setTrajectoryReference(
+     862             :       const mrs_msgs::TrajectoryReference trajectory_in);
+     863             : 
+     864             :   // publishes
+     865             :   void publish(void);
+     866             : 
+     867             :   bool loadConfigFile(const std::string& file_path, const std::string ns);
+     868             : 
+     869             :   double getMass(void);
+     870             : 
+     871             :   // publishes rviz-visualizable control reference
+     872             :   void publishControlReferenceOdom(const std::optional<mrs_msgs::TrackerCommand>& tracker_command, const Controller::ControlOutput& control_output);
+     873             : 
+     874             :   void initializeControlOutput(void);
+     875             : 
+     876             :   // tell the mrs_odometry to disable its callbacks
+     877             :   void odometryCallbacksSrv(const bool input);
+     878             : 
+     879             :   mrs_msgs::ReferenceStamped velocityReferenceToReference(const mrs_msgs::VelocityReferenceStamped& vel_reference);
+     880             : 
+     881             :   void                          shutdown();
+     882             :   void                          setCallbacks(bool in);
+     883             :   bool                          isOffboard(void);
+     884             :   bool                          elandSrv(void);
+     885             :   std::tuple<bool, std::string> arming(const bool input);
+     886             : 
+     887             :   // safety functions impl
+     888             :   std::tuple<bool, std::string> ehover(void);
+     889             :   std::tuple<bool, std::string> hover(void);
+     890             :   std::tuple<bool, std::string> startTrajectoryTracking(void);
+     891             :   std::tuple<bool, std::string> stopTrajectoryTracking(void);
+     892             :   std::tuple<bool, std::string> resumeTrajectoryTracking(void);
+     893             :   std::tuple<bool, std::string> gotoTrajectoryStart(void);
+     894             :   std::tuple<bool, std::string> eland(void);
+     895             :   std::tuple<bool, std::string> failsafe(void);
+     896             :   std::tuple<bool, std::string> escalatingFailsafe(void);
+     897             : 
+     898             :   EscalatingFailsafeStates_t getNextEscFailsafeState(void);
+     899             : };
+     900             : 
+     901             : //}
+     902             : 
+     903             : /* //{ onInit() */
+     904             : 
+     905           7 : void ControlManager::onInit() {
+     906           7 :   preinitialize();
+     907           7 : }
+     908             : 
+     909             : //}
+     910             : 
+     911             : /* preinitialize() //{ */
+     912             : 
+     913           7 : void ControlManager::preinitialize(void) {
+     914             : 
+     915           7 :   nh_ = nodelet::Nodelet::getMTPrivateNodeHandle();
+     916             : 
+     917           7 :   ros::Time::waitForValid();
+     918             : 
+     919           7 :   mrs_lib::SubscribeHandlerOptions shopts;
+     920           7 :   shopts.nh                 = nh_;
+     921           7 :   shopts.node_name          = "ControlManager";
+     922           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+     923           7 :   shopts.threadsafe         = true;
+     924           7 :   shopts.autostart          = true;
+     925           7 :   shopts.queue_size         = 10;
+     926           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     927             : 
+     928           7 :   sh_hw_api_capabilities_ = mrs_lib::SubscribeHandler<mrs_msgs::HwApiCapabilities>(shopts, "hw_api_capabilities_in");
+     929             : 
+     930           7 :   timer_hw_api_capabilities_ = nh_.createTimer(ros::Rate(1.0), &ControlManager::timerHwApiCapabilities, this);
+     931           7 : }
+     932             : 
+     933             : //}
+     934             : 
+     935             : /* initialize() //{ */
+     936             : 
+     937           7 : void ControlManager::initialize(void) {
+     938             : 
+     939           7 :   joystick_start_press_time_      = ros::Time(0);
+     940           7 :   joystick_failsafe_press_time_   = ros::Time(0);
+     941           7 :   joystick_eland_press_time_      = ros::Time(0);
+     942           7 :   escalating_failsafe_time_       = ros::Time(0);
+     943           7 :   controller_tracker_switch_time_ = ros::Time(0);
+     944             : 
+     945           7 :   ROS_INFO("[ControlManager]: initializing");
+     946             : 
+     947             :   // --------------------------------------------------------------
+     948             :   // |         common handler for trackers and controllers        |
+     949             :   // --------------------------------------------------------------
+     950             : 
+     951           7 :   common_handlers_ = std::make_shared<mrs_uav_managers::control_manager::CommonHandlers_t>();
+     952             : 
+     953             :   // --------------------------------------------------------------
+     954             :   // |                           params                           |
+     955             :   // --------------------------------------------------------------
+     956             : 
+     957          14 :   mrs_lib::ParamLoader param_loader(nh_, "ControlManager");
+     958             : 
+     959           7 :   param_loader.loadParam("custom_config", _custom_config_);
+     960           7 :   param_loader.loadParam("platform_config", _platform_config_);
+     961           7 :   param_loader.loadParam("world_config", _world_config_);
+     962           7 :   param_loader.loadParam("network_config", _network_config_);
+     963             : 
+     964           7 :   if (_custom_config_ != "") {
+     965           7 :     param_loader.addYamlFile(_custom_config_);
+     966             :   }
+     967             : 
+     968           7 :   if (_platform_config_ != "") {
+     969           7 :     param_loader.addYamlFile(_platform_config_);
+     970             :   }
+     971             : 
+     972           7 :   if (_world_config_ != "") {
+     973           7 :     param_loader.addYamlFile(_world_config_);
+     974             :   }
+     975             : 
+     976           7 :   if (_network_config_ != "") {
+     977           7 :     param_loader.addYamlFile(_network_config_);
+     978             :   }
+     979             : 
+     980           7 :   param_loader.addYamlFileFromParam("private_config");
+     981           7 :   param_loader.addYamlFileFromParam("public_config");
+     982           7 :   param_loader.addYamlFileFromParam("private_trackers");
+     983           7 :   param_loader.addYamlFileFromParam("private_controllers");
+     984           7 :   param_loader.addYamlFileFromParam("public_controllers");
+     985             : 
+     986             :   // params passed from the launch file are not prefixed
+     987           7 :   param_loader.loadParam("uav_name", _uav_name_);
+     988           7 :   param_loader.loadParam("body_frame", _body_frame_);
+     989           7 :   param_loader.loadParam("enable_profiler", _profiler_enabled_);
+     990           7 :   param_loader.loadParam("uav_mass", _uav_mass_);
+     991           7 :   param_loader.loadParam("body_disturbance_x", _initial_body_disturbance_x_);
+     992           7 :   param_loader.loadParam("body_disturbance_y", _initial_body_disturbance_y_);
+     993           7 :   param_loader.loadParam("g", common_handlers_->g);
+     994             : 
+     995             :   // motor params are also not prefixed, since they are common to more nodes
+     996           7 :   param_loader.loadParam("motor_params/a", common_handlers_->throttle_model.A);
+     997           7 :   param_loader.loadParam("motor_params/b", common_handlers_->throttle_model.B);
+     998           7 :   param_loader.loadParam("motor_params/n_motors", common_handlers_->throttle_model.n_motors);
+     999             : 
+    1000             :   // | ----------------------- safety area ---------------------- |
+    1001             : 
+    1002             :   bool use_safety_area;
+    1003           7 :   param_loader.loadParam("safety_area/enabled", use_safety_area);
+    1004           7 :   use_safety_area_ = use_safety_area;
+    1005             : 
+    1006           7 :   param_loader.loadParam("safety_area/horizontal/frame_name", _safety_area_horizontal_frame_);
+    1007             : 
+    1008           7 :   param_loader.loadParam("safety_area/vertical/frame_name", _safety_area_vertical_frame_);
+    1009           7 :   param_loader.loadParam("safety_area/vertical/min_z", _safety_area_min_z_);
+    1010           7 :   param_loader.loadParam("safety_area/vertical/max_z", _safety_area_max_z_);
+    1011             : 
+    1012           7 :   if (use_safety_area_) {
+    1013             : 
+    1014          12 :     Eigen::MatrixXd border_points = param_loader.loadMatrixDynamic2("safety_area/horizontal/points", -1, 2);
+    1015             : 
+    1016             :     try {
+    1017             : 
+    1018           8 :       std::vector<Eigen::MatrixXd> polygon_obstacle_points;
+    1019           4 :       std::vector<Eigen::MatrixXd> point_obstacle_points;
+    1020             : 
+    1021           4 :       safety_zone_ = std::make_unique<mrs_lib::SafetyZone>(border_points);
+    1022             :     }
+    1023             : 
+    1024           0 :     catch (mrs_lib::SafetyZone::BorderError& e) {
+    1025           0 :       ROS_ERROR("[ControlManager]: SafetyArea: wrong configruation for the safety zone border polygon");
+    1026           0 :       ros::shutdown();
+    1027             :     }
+    1028           0 :     catch (...) {
+    1029           0 :       ROS_ERROR("[ControlManager]: SafetyArea: unhandled exception!");
+    1030           0 :       ros::shutdown();
+    1031             :     }
+    1032             : 
+    1033           4 :     ROS_INFO("[ControlManager]: safety area initialized");
+    1034             :   }
+    1035             : 
+    1036           7 :   param_loader.setPrefix("mrs_uav_managers/control_manager/");
+    1037             : 
+    1038           7 :   param_loader.loadParam("state_input", _state_input_);
+    1039             : 
+    1040           7 :   if (!(_state_input_ == INPUT_UAV_STATE || _state_input_ == INPUT_ODOMETRY)) {
+    1041           0 :     ROS_ERROR("[ControlManager]: the state_input parameter has to be in {0, 1}");
+    1042           0 :     ros::shutdown();
+    1043             :   }
+    1044             : 
+    1045           7 :   param_loader.loadParam("safety/min_throttle_null_tracker", _min_throttle_null_tracker_);
+    1046           7 :   param_loader.loadParam("safety/ehover_tracker", _ehover_tracker_name_);
+    1047           7 :   param_loader.loadParam("safety/failsafe_controller", _failsafe_controller_name_);
+    1048             : 
+    1049           7 :   param_loader.loadParam("safety/eland/controller", _eland_controller_name_);
+    1050           7 :   param_loader.loadParam("safety/eland/cutoff_mass_factor", _elanding_cutoff_mass_factor_);
+    1051           7 :   param_loader.loadParam("safety/eland/cutoff_timeout", _elanding_cutoff_timeout_);
+    1052           7 :   param_loader.loadParam("safety/eland/timer_rate", _elanding_timer_rate_);
+    1053           7 :   param_loader.loadParam("safety/eland/disarm", _eland_disarm_enabled_);
+    1054             : 
+    1055           7 :   param_loader.loadParam("safety/escalating_failsafe/service/enabled", _service_escalating_failsafe_enabled_);
+    1056           7 :   param_loader.loadParam("safety/escalating_failsafe/rc/enabled", _rc_escalating_failsafe_enabled_);
+    1057           7 :   param_loader.loadParam("safety/escalating_failsafe/rc/channel_number", _rc_escalating_failsafe_channel_);
+    1058           7 :   param_loader.loadParam("safety/escalating_failsafe/rc/threshold", _rc_escalating_failsafe_threshold_);
+    1059           7 :   param_loader.loadParam("safety/escalating_failsafe/timeout", _escalating_failsafe_timeout_);
+    1060           7 :   param_loader.loadParam("safety/escalating_failsafe/ehover", _escalating_failsafe_ehover_);
+    1061           7 :   param_loader.loadParam("safety/escalating_failsafe/eland", _escalating_failsafe_eland_);
+    1062           7 :   param_loader.loadParam("safety/escalating_failsafe/failsafe", _escalating_failsafe_failsafe_);
+    1063             : 
+    1064           7 :   param_loader.loadParam("safety/tilt_limit/eland/enabled", _tilt_limit_eland_enabled_);
+    1065           7 :   param_loader.loadParam("safety/tilt_limit/eland/limit", _tilt_limit_eland_);
+    1066             : 
+    1067           7 :   _tilt_limit_eland_ = M_PI * (_tilt_limit_eland_ / 180.0);
+    1068             : 
+    1069           7 :   if (_tilt_limit_eland_enabled_ && fabs(_tilt_limit_eland_) < 1e-3) {
+    1070           0 :     ROS_ERROR("[ControlManager]: safety/tilt_limit/eland/enabled = 'TRUE' but the limit is too low");
+    1071           0 :     ros::shutdown();
+    1072             :   }
+    1073             : 
+    1074           7 :   param_loader.loadParam("safety/tilt_limit/disarm/enabled", _tilt_limit_disarm_enabled_);
+    1075           7 :   param_loader.loadParam("safety/tilt_limit/disarm/limit", _tilt_limit_disarm_);
+    1076             : 
+    1077           7 :   _tilt_limit_disarm_ = M_PI * (_tilt_limit_disarm_ / 180.0);
+    1078             : 
+    1079           7 :   if (_tilt_limit_disarm_enabled_ && fabs(_tilt_limit_disarm_) < 1e-3) {
+    1080           0 :     ROS_ERROR("[ControlManager]: safety/tilt_limit/disarm/enabled = 'TRUE' but the limit is too low");
+    1081           0 :     ros::shutdown();
+    1082             :   }
+    1083             : 
+    1084           7 :   param_loader.loadParam("safety/yaw_error_eland/enabled", _yaw_error_eland_enabled_);
+    1085           7 :   param_loader.loadParam("safety/yaw_error_eland/limit", _yaw_error_eland_);
+    1086             : 
+    1087           7 :   _yaw_error_eland_ = M_PI * (_yaw_error_eland_ / 180.0);
+    1088             : 
+    1089           7 :   if (_yaw_error_eland_enabled_ && fabs(_yaw_error_eland_) < 1e-3) {
+    1090           0 :     ROS_ERROR("[ControlManager]: safety/yaw_error_eland/enabled = 'TRUE' but the limit is too low");
+    1091           0 :     ros::shutdown();
+    1092             :   }
+    1093             : 
+    1094           7 :   param_loader.loadParam("status_timer_rate", _status_timer_rate_);
+    1095           7 :   param_loader.loadParam("safety/safety_timer_rate", _safety_timer_rate_);
+    1096           7 :   param_loader.loadParam("safety/failsafe_timer_rate", _failsafe_timer_rate_);
+    1097           7 :   param_loader.loadParam("safety/rc_emergency_handoff/enabled", _rc_emergency_handoff_);
+    1098             : 
+    1099           7 :   param_loader.loadParam("safety/odometry_max_missing_time", _uav_state_max_missing_time_);
+    1100           7 :   param_loader.loadParam("safety/odometry_innovation_eland/enabled", _odometry_innovation_check_enabled_);
+    1101             : 
+    1102           7 :   param_loader.loadParam("safety/tilt_error_disarm/enabled", _tilt_error_disarm_enabled_);
+    1103           7 :   param_loader.loadParam("safety/tilt_error_disarm/timeout", _tilt_error_disarm_timeout_);
+    1104           7 :   param_loader.loadParam("safety/tilt_error_disarm/error_threshold", _tilt_error_disarm_threshold_);
+    1105             : 
+    1106           7 :   _tilt_error_disarm_threshold_ = M_PI * (_tilt_error_disarm_threshold_ / 180.0);
+    1107             : 
+    1108           7 :   if (_tilt_error_disarm_enabled_ && fabs(_tilt_error_disarm_threshold_) < 1e-3) {
+    1109           0 :     ROS_ERROR("[ControlManager]: safety/tilt_error_disarm/enabled = 'TRUE' but the limit is too low");
+    1110           0 :     ros::shutdown();
+    1111             :   }
+    1112             : 
+    1113             :   // default constraints
+    1114             : 
+    1115           7 :   param_loader.loadParam("default_constraints/horizontal/speed", current_constraints_.constraints.horizontal_speed);
+    1116           7 :   param_loader.loadParam("default_constraints/horizontal/acceleration", current_constraints_.constraints.horizontal_acceleration);
+    1117           7 :   param_loader.loadParam("default_constraints/horizontal/jerk", current_constraints_.constraints.horizontal_jerk);
+    1118           7 :   param_loader.loadParam("default_constraints/horizontal/snap", current_constraints_.constraints.horizontal_snap);
+    1119             : 
+    1120           7 :   param_loader.loadParam("default_constraints/vertical/ascending/speed", current_constraints_.constraints.vertical_ascending_speed);
+    1121           7 :   param_loader.loadParam("default_constraints/vertical/ascending/acceleration", current_constraints_.constraints.vertical_ascending_acceleration);
+    1122           7 :   param_loader.loadParam("default_constraints/vertical/ascending/jerk", current_constraints_.constraints.vertical_ascending_jerk);
+    1123           7 :   param_loader.loadParam("default_constraints/vertical/ascending/snap", current_constraints_.constraints.vertical_ascending_snap);
+    1124             : 
+    1125           7 :   param_loader.loadParam("default_constraints/vertical/descending/speed", current_constraints_.constraints.vertical_descending_speed);
+    1126           7 :   param_loader.loadParam("default_constraints/vertical/descending/acceleration", current_constraints_.constraints.vertical_descending_acceleration);
+    1127           7 :   param_loader.loadParam("default_constraints/vertical/descending/jerk", current_constraints_.constraints.vertical_descending_jerk);
+    1128           7 :   param_loader.loadParam("default_constraints/vertical/descending/snap", current_constraints_.constraints.vertical_descending_snap);
+    1129             : 
+    1130           7 :   param_loader.loadParam("default_constraints/heading/speed", current_constraints_.constraints.heading_speed);
+    1131           7 :   param_loader.loadParam("default_constraints/heading/acceleration", current_constraints_.constraints.heading_acceleration);
+    1132           7 :   param_loader.loadParam("default_constraints/heading/jerk", current_constraints_.constraints.heading_jerk);
+    1133           7 :   param_loader.loadParam("default_constraints/heading/snap", current_constraints_.constraints.heading_snap);
+    1134             : 
+    1135           7 :   param_loader.loadParam("default_constraints/angular_speed/roll", current_constraints_.constraints.roll_rate);
+    1136           7 :   param_loader.loadParam("default_constraints/angular_speed/pitch", current_constraints_.constraints.pitch_rate);
+    1137           7 :   param_loader.loadParam("default_constraints/angular_speed/yaw", current_constraints_.constraints.yaw_rate);
+    1138             : 
+    1139           7 :   param_loader.loadParam("default_constraints/tilt", current_constraints_.constraints.tilt);
+    1140             : 
+    1141           7 :   current_constraints_.constraints.tilt = M_PI * (current_constraints_.constraints.tilt / 180.0);
+    1142             : 
+    1143             :   // joystick
+    1144             : 
+    1145           7 :   param_loader.loadParam("joystick/enabled", _joystick_enabled_);
+    1146           7 :   param_loader.loadParam("joystick/mode", _joystick_mode_);
+    1147           7 :   param_loader.loadParam("joystick/carrot_distance", _joystick_carrot_distance_);
+    1148           7 :   param_loader.loadParam("joystick/joystick_timer_rate", _joystick_timer_rate_);
+    1149           7 :   param_loader.loadParam("joystick/attitude_control/tracker", _joystick_tracker_name_);
+    1150           7 :   param_loader.loadParam("joystick/attitude_control/controller", _joystick_controller_name_);
+    1151           7 :   param_loader.loadParam("joystick/attitude_control/fallback/tracker", _joystick_fallback_tracker_name_);
+    1152           7 :   param_loader.loadParam("joystick/attitude_control/fallback/controller", _joystick_fallback_controller_name_);
+    1153             : 
+    1154           7 :   param_loader.loadParam("joystick/channels/A", _channel_A_);
+    1155           7 :   param_loader.loadParam("joystick/channels/B", _channel_B_);
+    1156           7 :   param_loader.loadParam("joystick/channels/X", _channel_X_);
+    1157           7 :   param_loader.loadParam("joystick/channels/Y", _channel_Y_);
+    1158           7 :   param_loader.loadParam("joystick/channels/start", _channel_start_);
+    1159           7 :   param_loader.loadParam("joystick/channels/back", _channel_back_);
+    1160           7 :   param_loader.loadParam("joystick/channels/LT", _channel_LT_);
+    1161           7 :   param_loader.loadParam("joystick/channels/RT", _channel_RT_);
+    1162           7 :   param_loader.loadParam("joystick/channels/L_joy", _channel_L_joy_);
+    1163           7 :   param_loader.loadParam("joystick/channels/R_joy", _channel_R_joy_);
+    1164             : 
+    1165             :   // load channels
+    1166           7 :   param_loader.loadParam("joystick/channels/pitch", _channel_pitch_);
+    1167           7 :   param_loader.loadParam("joystick/channels/roll", _channel_roll_);
+    1168           7 :   param_loader.loadParam("joystick/channels/heading", _channel_heading_);
+    1169           7 :   param_loader.loadParam("joystick/channels/throttle", _channel_throttle_);
+    1170             : 
+    1171             :   // load channel multipliers
+    1172           7 :   param_loader.loadParam("joystick/channel_multipliers/pitch", _channel_mult_pitch_);
+    1173           7 :   param_loader.loadParam("joystick/channel_multipliers/roll", _channel_mult_roll_);
+    1174           7 :   param_loader.loadParam("joystick/channel_multipliers/heading", _channel_mult_heading_);
+    1175           7 :   param_loader.loadParam("joystick/channel_multipliers/throttle", _channel_mult_throttle_);
+    1176             : 
+    1177             :   bool bumper_enabled;
+    1178           7 :   param_loader.loadParam("obstacle_bumper/enabled", bumper_enabled);
+    1179           7 :   bumper_enabled_ = bumper_enabled;
+    1180             : 
+    1181           7 :   param_loader.loadParam("obstacle_bumper/switch_tracker", _bumper_switch_tracker_);
+    1182           7 :   param_loader.loadParam("obstacle_bumper/switch_controller", _bumper_switch_controller_);
+    1183           7 :   param_loader.loadParam("obstacle_bumper/tracker", _bumper_tracker_name_);
+    1184           7 :   param_loader.loadParam("obstacle_bumper/controller", _bumper_controller_name_);
+    1185           7 :   param_loader.loadParam("obstacle_bumper/timer_rate", _bumper_timer_rate_);
+    1186             : 
+    1187           7 :   param_loader.loadParam("obstacle_bumper/horizontal/threshold_distance", _bumper_horizontal_distance_);
+    1188           7 :   param_loader.loadParam("obstacle_bumper/vertical/threshold_distance", _bumper_vertical_distance_);
+    1189             : 
+    1190           7 :   param_loader.loadParam("obstacle_bumper/horizontal/overshoot", _bumper_horizontal_overshoot_);
+    1191           7 :   param_loader.loadParam("obstacle_bumper/vertical/overshoot", _bumper_vertical_overshoot_);
+    1192             : 
+    1193           7 :   param_loader.loadParam("safety/tracker_error_action", _tracker_error_action_);
+    1194             : 
+    1195           7 :   param_loader.loadParam("trajectory_tracking/snap_to_safety_area", _snap_trajectory_to_safety_area_);
+    1196             : 
+    1197             :   // check the values of tracker error action
+    1198           7 :   if (_tracker_error_action_ != ELAND_STR && _tracker_error_action_ != EHOVER_STR) {
+    1199           0 :     ROS_ERROR("[ControlManager]: the tracker_error_action parameter (%s) is not correct, requires {%s, %s}", _tracker_error_action_.c_str(), ELAND_STR,
+    1200             :               EHOVER_STR);
+    1201           0 :     ros::shutdown();
+    1202             :   }
+    1203             : 
+    1204           7 :   param_loader.loadParam("rc_joystick/enabled", _rc_goto_enabled_);
+    1205           7 :   param_loader.loadParam("rc_joystick/channel_number", _rc_joystick_channel_);
+    1206           7 :   param_loader.loadParam("rc_joystick/horizontal_speed", _rc_horizontal_speed_);
+    1207           7 :   param_loader.loadParam("rc_joystick/vertical_speed", _rc_vertical_speed_);
+    1208           7 :   param_loader.loadParam("rc_joystick/heading_rate", _rc_heading_rate_);
+    1209             : 
+    1210           7 :   param_loader.loadParam("rc_joystick/channels/pitch", _rc_channel_pitch_);
+    1211           7 :   param_loader.loadParam("rc_joystick/channels/roll", _rc_channel_roll_);
+    1212           7 :   param_loader.loadParam("rc_joystick/channels/heading", _rc_channel_heading_);
+    1213           7 :   param_loader.loadParam("rc_joystick/channels/throttle", _rc_channel_throttle_);
+    1214             : 
+    1215           7 :   param_loader.loadParam("automatic_pc_shutdown/enabled", _automatic_pc_shutdown_enabled_);
+    1216             : 
+    1217           7 :   param_loader.loadParam("pirouette/speed", _pirouette_speed_);
+    1218           7 :   param_loader.loadParam("pirouette/timer_rate", _pirouette_timer_rate_);
+    1219             : 
+    1220           7 :   param_loader.loadParam("safety/parachute/enabled", _parachute_enabled_);
+    1221             : 
+    1222             :   // --------------------------------------------------------------
+    1223             :   // |             initialize the last control output             |
+    1224             :   // --------------------------------------------------------------
+    1225             : 
+    1226           7 :   initializeControlOutput();
+    1227             : 
+    1228             :   // | --------------------- tf transformer --------------------- |
+    1229             : 
+    1230           7 :   transformer_ = std::make_shared<mrs_lib::Transformer>(nh_, "ControlManager");
+    1231           7 :   transformer_->setDefaultPrefix(_uav_name_);
+    1232           7 :   transformer_->retryLookupNewest(true);
+    1233             : 
+    1234             :   // | ------------------- scope timer logger ------------------- |
+    1235             : 
+    1236           7 :   param_loader.loadParam("scope_timer/enabled", scope_timer_enabled_);
+    1237          21 :   const std::string scope_timer_log_filename = param_loader.loadParam2("scope_timer/log_filename", std::string(""));
+    1238           7 :   scope_timer_logger_                        = std::make_shared<mrs_lib::ScopeTimerLogger>(scope_timer_log_filename, scope_timer_enabled_);
+    1239             : 
+    1240             :   // bind transformer to trackers and controllers for use
+    1241           7 :   common_handlers_->transformer = transformer_;
+    1242             : 
+    1243             :   // bind scope timer to trackers and controllers for use
+    1244           7 :   common_handlers_->scope_timer.enabled = scope_timer_enabled_;
+    1245           7 :   common_handlers_->scope_timer.logger  = scope_timer_logger_;
+    1246             : 
+    1247           7 :   common_handlers_->safety_area.use_safety_area       = use_safety_area_;
+    1248           7 :   common_handlers_->safety_area.isPointInSafetyArea2d = boost::bind(&ControlManager::isPointInSafetyArea2d, this, _1);
+    1249           7 :   common_handlers_->safety_area.isPointInSafetyArea3d = boost::bind(&ControlManager::isPointInSafetyArea3d, this, _1);
+    1250           7 :   common_handlers_->safety_area.getMinZ               = boost::bind(&ControlManager::getMinZ, this, _1);
+    1251           7 :   common_handlers_->safety_area.getMaxZ               = boost::bind(&ControlManager::getMaxZ, this, _1);
+    1252             : 
+    1253           7 :   common_handlers_->getMass = boost::bind(&ControlManager::getMass, this);
+    1254             : 
+    1255           7 :   common_handlers_->detailed_model_params = loadDetailedUavModelParams(nh_, "ControlManager", _platform_config_, _custom_config_);
+    1256             : 
+    1257           7 :   common_handlers_->control_output_modalities = _hw_api_inputs_;
+    1258             : 
+    1259           7 :   common_handlers_->uav_name = _uav_name_;
+    1260             : 
+    1261           7 :   common_handlers_->parent_nh = nh_;
+    1262             : 
+    1263             :   // --------------------------------------------------------------
+    1264             :   // |                        load trackers                       |
+    1265             :   // --------------------------------------------------------------
+    1266             : 
+    1267          14 :   std::vector<std::string> custom_trackers;
+    1268             : 
+    1269           7 :   param_loader.loadParam("mrs_trackers", _tracker_names_);
+    1270           7 :   param_loader.loadParam("trackers", custom_trackers);
+    1271             : 
+    1272           7 :   if (!custom_trackers.empty()) {
+    1273           0 :     _tracker_names_.insert(_tracker_names_.end(), custom_trackers.begin(), custom_trackers.end());
+    1274             :   }
+    1275             : 
+    1276           7 :   param_loader.loadParam("null_tracker", _null_tracker_name_);
+    1277           7 :   param_loader.loadParam("landing_takeoff_tracker", _landoff_tracker_name_);
+    1278             : 
+    1279           7 :   tracker_loader_ = std::make_unique<pluginlib::ClassLoader<mrs_uav_managers::Tracker>>("mrs_uav_managers", "mrs_uav_managers::Tracker");
+    1280             : 
+    1281          49 :   for (int i = 0; i < int(_tracker_names_.size()); i++) {
+    1282             : 
+    1283          84 :     std::string tracker_name = _tracker_names_[i];
+    1284             : 
+    1285             :     // load the controller parameters
+    1286          84 :     std::string address;
+    1287          84 :     std::string name_space;
+    1288             :     bool        human_switchable;
+    1289             : 
+    1290          42 :     param_loader.loadParam(tracker_name + "/address", address);
+    1291          42 :     param_loader.loadParam(tracker_name + "/namespace", name_space);
+    1292          42 :     param_loader.loadParam(tracker_name + "/human_switchable", human_switchable, false);
+    1293             : 
+    1294         126 :     TrackerParams new_tracker(address, name_space, human_switchable);
+    1295          42 :     trackers_.insert(std::pair<std::string, TrackerParams>(tracker_name, new_tracker));
+    1296             : 
+    1297             :     try {
+    1298          42 :       ROS_INFO("[ControlManager]: loading the tracker '%s'", new_tracker.address.c_str());
+    1299          42 :       tracker_list_.push_back(tracker_loader_->createInstance(new_tracker.address.c_str()));
+    1300             :     }
+    1301           0 :     catch (pluginlib::CreateClassException& ex1) {
+    1302           0 :       ROS_ERROR("[ControlManager]: CreateClassException for the tracker '%s'", new_tracker.address.c_str());
+    1303           0 :       ROS_ERROR("[ControlManager]: Error: %s", ex1.what());
+    1304           0 :       ros::shutdown();
+    1305             :     }
+    1306           0 :     catch (pluginlib::PluginlibException& ex) {
+    1307           0 :       ROS_ERROR("[ControlManager]: PluginlibException for the tracker '%s'", new_tracker.address.c_str());
+    1308           0 :       ROS_ERROR("[ControlManager]: Error: %s", ex.what());
+    1309           0 :       ros::shutdown();
+    1310             :     }
+    1311             :   }
+    1312             : 
+    1313           7 :   ROS_INFO("[ControlManager]: trackers were loaded");
+    1314             : 
+    1315          49 :   for (int i = 0; i < int(tracker_list_.size()); i++) {
+    1316             : 
+    1317          42 :     std::map<std::string, TrackerParams>::iterator it;
+    1318          42 :     it = trackers_.find(_tracker_names_[i]);
+    1319             : 
+    1320             :     // create private handlers
+    1321             :     std::shared_ptr<mrs_uav_managers::control_manager::PrivateHandlers_t> private_handlers =
+    1322          84 :         std::make_shared<mrs_uav_managers::control_manager::PrivateHandlers_t>();
+    1323             : 
+    1324          42 :     private_handlers->loadConfigFile = boost::bind(&ControlManager::loadConfigFile, this, _1, it->second.name_space);
+    1325          42 :     private_handlers->name_space     = it->second.name_space;
+    1326          42 :     private_handlers->runtime_name   = _tracker_names_[i];
+    1327          42 :     private_handlers->param_loader   = std::make_unique<mrs_lib::ParamLoader>(ros::NodeHandle(nh_, it->second.name_space), _tracker_names_[i]);
+    1328             : 
+    1329          42 :     if (_custom_config_ != "") {
+    1330          42 :       private_handlers->param_loader->addYamlFile(_custom_config_);
+    1331             :     }
+    1332             : 
+    1333          42 :     if (_platform_config_ != "") {
+    1334          42 :       private_handlers->param_loader->addYamlFile(_platform_config_);
+    1335             :     }
+    1336             : 
+    1337          42 :     if (_world_config_ != "") {
+    1338          42 :       private_handlers->param_loader->addYamlFile(_world_config_);
+    1339             :     }
+    1340             : 
+    1341          42 :     if (_network_config_ != "") {
+    1342          42 :       private_handlers->param_loader->addYamlFile(_network_config_);
+    1343             :     }
+    1344             : 
+    1345          42 :     bool success = false;
+    1346             : 
+    1347             :     try {
+    1348          42 :       ROS_INFO("[ControlManager]: initializing the tracker '%s'", it->second.address.c_str());
+    1349          42 :       success = tracker_list_[i]->initialize(ros::NodeHandle(nh_, it->second.name_space), common_handlers_, private_handlers);
+    1350             :     }
+    1351           0 :     catch (std::runtime_error& ex) {
+    1352           0 :       ROS_ERROR("[ControlManager]: exception caught during tracker initialization: '%s'", ex.what());
+    1353             :     }
+    1354             : 
+    1355          42 :     if (!success) {
+    1356           0 :       ROS_ERROR("[ControlManager]: failed to initialize the tracker '%s'", it->second.address.c_str());
+    1357           0 :       ros::shutdown();
+    1358             :     }
+    1359             :   }
+    1360             : 
+    1361           7 :   ROS_INFO("[ControlManager]: trackers were initialized");
+    1362             : 
+    1363             :   // --------------------------------------------------------------
+    1364             :   // |           check the existance of selected trackers         |
+    1365             :   // --------------------------------------------------------------
+    1366             : 
+    1367             :   // | ------ check for the existance of the hover tracker ------ |
+    1368             : 
+    1369             :   // check if the hover_tracker is within the loaded trackers
+    1370             :   {
+    1371           7 :     auto idx = idxInVector(_ehover_tracker_name_, _tracker_names_);
+    1372             : 
+    1373           7 :     if (idx) {
+    1374           7 :       _ehover_tracker_idx_ = idx.value();
+    1375             :     } else {
+    1376           0 :       ROS_ERROR("[ControlManager]: the safety/hover_tracker (%s) is not within the loaded trackers", _ehover_tracker_name_.c_str());
+    1377           0 :       ros::shutdown();
+    1378             :     }
+    1379             :   }
+    1380             : 
+    1381             :   // | ----- check for the existence of the landoff tracker ----- |
+    1382             : 
+    1383             :   {
+    1384           7 :     auto idx = idxInVector(_landoff_tracker_name_, _tracker_names_);
+    1385             : 
+    1386           7 :     if (idx) {
+    1387           7 :       _landoff_tracker_idx_ = idx.value();
+    1388             :     } else {
+    1389           0 :       ROS_ERROR("[ControlManager]: the landoff tracker (%s) is not within the loaded trackers", _landoff_tracker_name_.c_str());
+    1390           0 :       ros::shutdown();
+    1391             :     }
+    1392             :   }
+    1393             : 
+    1394             :   // | ------- check for the existence of the null tracker ------ |
+    1395             : 
+    1396             :   {
+    1397           7 :     auto idx = idxInVector(_null_tracker_name_, _tracker_names_);
+    1398             : 
+    1399           7 :     if (idx) {
+    1400           7 :       _null_tracker_idx_ = idx.value();
+    1401             :     } else {
+    1402           0 :       ROS_ERROR("[ControlManager]: the null tracker (%s) is not within the loaded trackers", _null_tracker_name_.c_str());
+    1403           0 :       ros::shutdown();
+    1404             :     }
+    1405             :   }
+    1406             : 
+    1407             :   // --------------------------------------------------------------
+    1408             :   // |         check existance of trackers for joystick           |
+    1409             :   // --------------------------------------------------------------
+    1410             : 
+    1411           7 :   if (_joystick_enabled_) {
+    1412             : 
+    1413           7 :     auto idx = idxInVector(_joystick_tracker_name_, _tracker_names_);
+    1414             : 
+    1415           7 :     if (idx) {
+    1416           7 :       _joystick_tracker_idx_ = idx.value();
+    1417             :     } else {
+    1418           0 :       ROS_ERROR("[ControlManager]: the joystick tracker (%s) is not within the loaded trackers", _joystick_tracker_name_.c_str());
+    1419           0 :       ros::shutdown();
+    1420             :     }
+    1421             :   }
+    1422             : 
+    1423           7 :   if (_bumper_switch_tracker_) {
+    1424             : 
+    1425           7 :     auto idx = idxInVector(_bumper_tracker_name_, _tracker_names_);
+    1426             : 
+    1427           7 :     if (!idx) {
+    1428           0 :       ROS_ERROR("[ControlManager]: the bumper tracker (%s) is not within the loaded trackers", _bumper_tracker_name_.c_str());
+    1429           0 :       ros::shutdown();
+    1430             :     }
+    1431             :   }
+    1432             : 
+    1433             :   {
+    1434           7 :     auto idx = idxInVector(_joystick_fallback_tracker_name_, _tracker_names_);
+    1435             : 
+    1436           7 :     if (idx) {
+    1437           7 :       _joystick_fallback_tracker_idx_ = idx.value();
+    1438             :     } else {
+    1439           0 :       ROS_ERROR("[ControlManager]: the joystick fallback tracker (%s) is not within the loaded trackers", _joystick_fallback_tracker_name_.c_str());
+    1440           0 :       ros::shutdown();
+    1441             :     }
+    1442             :   }
+    1443             : 
+    1444             :   // --------------------------------------------------------------
+    1445             :   // |                    load the controllers                    |
+    1446             :   // --------------------------------------------------------------
+    1447             : 
+    1448          14 :   std::vector<std::string> custom_controllers;
+    1449             : 
+    1450           7 :   param_loader.loadParam("mrs_controllers", _controller_names_);
+    1451           7 :   param_loader.loadParam("controllers", custom_controllers);
+    1452             : 
+    1453           7 :   if (!custom_controllers.empty()) {
+    1454           0 :     _controller_names_.insert(_controller_names_.end(), custom_controllers.begin(), custom_controllers.end());
+    1455             :   }
+    1456             : 
+    1457           7 :   controller_loader_ = std::make_unique<pluginlib::ClassLoader<mrs_uav_managers::Controller>>("mrs_uav_managers", "mrs_uav_managers::Controller");
+    1458             : 
+    1459             :   // for each controller in the list
+    1460          42 :   for (int i = 0; i < int(_controller_names_.size()); i++) {
+    1461             : 
+    1462          70 :     std::string controller_name = _controller_names_[i];
+    1463             : 
+    1464             :     // load the controller parameters
+    1465          70 :     std::string address;
+    1466          70 :     std::string name_space;
+    1467             :     double      eland_threshold, failsafe_threshold, odometry_innovation_threshold;
+    1468             :     bool        human_switchable;
+    1469          35 :     param_loader.loadParam(controller_name + "/address", address);
+    1470          35 :     param_loader.loadParam(controller_name + "/namespace", name_space);
+    1471          35 :     param_loader.loadParam(controller_name + "/eland_threshold", eland_threshold);
+    1472          35 :     param_loader.loadParam(controller_name + "/failsafe_threshold", failsafe_threshold);
+    1473          35 :     param_loader.loadParam(controller_name + "/odometry_innovation_threshold", odometry_innovation_threshold);
+    1474          35 :     param_loader.loadParam(controller_name + "/human_switchable", human_switchable, false);
+    1475             : 
+    1476             :     // check if the controller can output some of the required outputs
+    1477             :     {
+    1478             : 
+    1479          35 :       ControlOutputModalities_t outputs;
+    1480          35 :       param_loader.loadParam(controller_name + "/outputs/actuators", outputs.actuators, false);
+    1481          35 :       param_loader.loadParam(controller_name + "/outputs/control_group", outputs.control_group, false);
+    1482          35 :       param_loader.loadParam(controller_name + "/outputs/attitude_rate", outputs.attitude_rate, false);
+    1483          35 :       param_loader.loadParam(controller_name + "/outputs/attitude", outputs.attitude, false);
+    1484          35 :       param_loader.loadParam(controller_name + "/outputs/acceleration_hdg_rate", outputs.acceleration_hdg_rate, false);
+    1485          35 :       param_loader.loadParam(controller_name + "/outputs/acceleration_hdg", outputs.acceleration_hdg, false);
+    1486          35 :       param_loader.loadParam(controller_name + "/outputs/velocity_hdg_rate", outputs.velocity_hdg_rate, false);
+    1487          35 :       param_loader.loadParam(controller_name + "/outputs/velocity_hdg", outputs.velocity_hdg, false);
+    1488          35 :       param_loader.loadParam(controller_name + "/outputs/position", outputs.position, false);
+    1489             : 
+    1490          35 :       bool meets_actuators             = (_hw_api_inputs_.actuators && outputs.actuators);
+    1491          35 :       bool meets_control_group         = (_hw_api_inputs_.control_group && outputs.control_group);
+    1492          35 :       bool meets_attitude_rate         = (_hw_api_inputs_.attitude_rate && outputs.attitude_rate);
+    1493          35 :       bool meets_attitude              = (_hw_api_inputs_.attitude && outputs.attitude);
+    1494          35 :       bool meets_acceleration_hdg_rate = (_hw_api_inputs_.acceleration_hdg_rate && outputs.acceleration_hdg_rate);
+    1495          35 :       bool meets_acceleration_hdg      = (_hw_api_inputs_.acceleration_hdg && outputs.acceleration_hdg);
+    1496          35 :       bool meets_velocity_hdg_rate     = (_hw_api_inputs_.velocity_hdg_rate && outputs.velocity_hdg_rate);
+    1497          35 :       bool meets_velocity_hdg          = (_hw_api_inputs_.velocity_hdg && outputs.velocity_hdg);
+    1498          35 :       bool meets_position              = (_hw_api_inputs_.position && outputs.position);
+    1499             : 
+    1500          35 :       bool meets_requirements = meets_actuators || meets_control_group || meets_attitude_rate || meets_attitude || meets_acceleration_hdg_rate ||
+    1501          70 :                                 meets_acceleration_hdg || meets_velocity_hdg_rate || meets_velocity_hdg || meets_position;
+    1502             : 
+    1503          35 :       if (!meets_requirements) {
+    1504             : 
+    1505           0 :         ROS_ERROR("[ControlManager]: the controller '%s' does not meet the control output requirements, which are some of the following",
+    1506             :                   controller_name.c_str());
+    1507             : 
+    1508           0 :         if (_hw_api_inputs_.actuators) {
+    1509           0 :           ROS_ERROR("[ControlManager]: - actuators");
+    1510             :         }
+    1511             : 
+    1512           0 :         if (_hw_api_inputs_.control_group) {
+    1513           0 :           ROS_ERROR("[ControlManager]: - control group");
+    1514             :         }
+    1515             : 
+    1516           0 :         if (_hw_api_inputs_.attitude_rate) {
+    1517           0 :           ROS_ERROR("[ControlManager]: - attitude rate");
+    1518             :         }
+    1519             : 
+    1520           0 :         if (_hw_api_inputs_.attitude) {
+    1521           0 :           ROS_ERROR("[ControlManager]: - attitude");
+    1522             :         }
+    1523             : 
+    1524           0 :         if (_hw_api_inputs_.acceleration_hdg_rate) {
+    1525           0 :           ROS_ERROR("[ControlManager]: - acceleration+hdg rate");
+    1526             :         }
+    1527             : 
+    1528           0 :         if (_hw_api_inputs_.acceleration_hdg) {
+    1529           0 :           ROS_ERROR("[ControlManager]: - acceleration+hdg");
+    1530             :         }
+    1531             : 
+    1532           0 :         if (_hw_api_inputs_.velocity_hdg_rate) {
+    1533           0 :           ROS_ERROR("[ControlManager]: - velocity+hdg rate");
+    1534             :         }
+    1535             : 
+    1536           0 :         if (_hw_api_inputs_.velocity_hdg) {
+    1537           0 :           ROS_ERROR("[ControlManager]: - velocity+hdg");
+    1538             :         }
+    1539             : 
+    1540           0 :         if (_hw_api_inputs_.position) {
+    1541           0 :           ROS_ERROR("[ControlManager]: - position");
+    1542             :         }
+    1543             : 
+    1544           0 :         ros::shutdown();
+    1545             :       }
+    1546             : 
+    1547          35 :       if ((_hw_api_inputs_.actuators || _hw_api_inputs_.control_group) && !common_handlers_->detailed_model_params) {
+    1548           0 :         ROS_ERROR(
+    1549             :             "[ControlManager]: the HW API supports 'actuators' or 'control_group' input, but the 'detailed uav model params' were not loaded sucessfully");
+    1550           0 :         ros::shutdown();
+    1551             :       }
+    1552             :     }
+    1553             : 
+    1554             :     // | --- alter the timer rates based on the hw capabilities --- |
+    1555             : 
+    1556          35 :     CONTROL_OUTPUT lowest_output = getLowestOuput(_hw_api_inputs_);
+    1557             : 
+    1558          35 :     if (lowest_output == ACTUATORS_CMD || lowest_output == CONTROL_GROUP) {
+    1559           0 :       _safety_timer_rate_     = 200.0;
+    1560           0 :       desired_uav_state_rate_ = 250.0;
+    1561          35 :     } else if (lowest_output == ATTITUDE_RATE || lowest_output == ATTITUDE) {
+    1562          35 :       _safety_timer_rate_     = 100.0;
+    1563          35 :       desired_uav_state_rate_ = 100.0;
+    1564           0 :     } else if (lowest_output == ACCELERATION_HDG_RATE || lowest_output == ACCELERATION_HDG) {
+    1565           0 :       _safety_timer_rate_     = 30.0;
+    1566           0 :       _status_timer_rate_     = 1.0;
+    1567           0 :       desired_uav_state_rate_ = 40.0;
+    1568             : 
+    1569           0 :       if (_uav_state_max_missing_time_ < 0.2) {
+    1570           0 :         _uav_state_max_missing_time_ = 0.2;
+    1571             :       }
+    1572           0 :     } else if (lowest_output >= VELOCITY_HDG_RATE) {
+    1573           0 :       _safety_timer_rate_     = 20.0;
+    1574           0 :       _status_timer_rate_     = 1.0;
+    1575           0 :       desired_uav_state_rate_ = 20.0;
+    1576             : 
+    1577           0 :       if (_uav_state_max_missing_time_ < 1.0) {
+    1578           0 :         _uav_state_max_missing_time_ = 1.0;
+    1579             :       }
+    1580             :     }
+    1581             : 
+    1582          35 :     if (eland_threshold == 0) {
+    1583           8 :       eland_threshold = 1e6;
+    1584             :     }
+    1585             : 
+    1586          35 :     if (failsafe_threshold == 0) {
+    1587           8 :       failsafe_threshold = 1e6;
+    1588             :     }
+    1589             : 
+    1590          35 :     if (odometry_innovation_threshold == 0) {
+    1591           9 :       odometry_innovation_threshold = 1e6;
+    1592             :     }
+    1593             : 
+    1594         105 :     ControllerParams new_controller(address, name_space, eland_threshold, failsafe_threshold, odometry_innovation_threshold, human_switchable);
+    1595          35 :     controllers_.insert(std::pair<std::string, ControllerParams>(controller_name, new_controller));
+    1596             : 
+    1597             :     try {
+    1598          35 :       ROS_INFO("[ControlManager]: loading the controller '%s'", new_controller.address.c_str());
+    1599          35 :       controller_list_.push_back(controller_loader_->createInstance(new_controller.address.c_str()));
+    1600             :     }
+    1601           0 :     catch (pluginlib::CreateClassException& ex1) {
+    1602           0 :       ROS_ERROR("[ControlManager]: CreateClassException for the controller '%s'", new_controller.address.c_str());
+    1603           0 :       ROS_ERROR("[ControlManager]: Error: %s", ex1.what());
+    1604           0 :       ros::shutdown();
+    1605             :     }
+    1606           0 :     catch (pluginlib::PluginlibException& ex) {
+    1607           0 :       ROS_ERROR("[ControlManager]: PluginlibException for the controller '%s'", new_controller.address.c_str());
+    1608           0 :       ROS_ERROR("[ControlManager]: Error: %s", ex.what());
+    1609           0 :       ros::shutdown();
+    1610             :     }
+    1611             :   }
+    1612             : 
+    1613           7 :   ROS_INFO("[ControlManager]: controllers were loaded");
+    1614             : 
+    1615          42 :   for (int i = 0; i < int(controller_list_.size()); i++) {
+    1616             : 
+    1617          35 :     std::map<std::string, ControllerParams>::iterator it;
+    1618          35 :     it = controllers_.find(_controller_names_[i]);
+    1619             : 
+    1620             :     // create private handlers
+    1621             :     std::shared_ptr<mrs_uav_managers::control_manager::PrivateHandlers_t> private_handlers =
+    1622          70 :         std::make_shared<mrs_uav_managers::control_manager::PrivateHandlers_t>();
+    1623             : 
+    1624          35 :     private_handlers->loadConfigFile = boost::bind(&ControlManager::loadConfigFile, this, _1, it->second.name_space);
+    1625          35 :     private_handlers->name_space     = it->second.name_space;
+    1626          35 :     private_handlers->runtime_name   = _controller_names_[i];
+    1627          35 :     private_handlers->param_loader   = std::make_unique<mrs_lib::ParamLoader>(ros::NodeHandle(nh_, it->second.name_space), _controller_names_[i]);
+    1628             : 
+    1629          35 :     if (_custom_config_ != "") {
+    1630          35 :       private_handlers->param_loader->addYamlFile(_custom_config_);
+    1631             :     }
+    1632             : 
+    1633          35 :     if (_platform_config_ != "") {
+    1634          35 :       private_handlers->param_loader->addYamlFile(_platform_config_);
+    1635             :     }
+    1636             : 
+    1637          35 :     if (_world_config_ != "") {
+    1638          35 :       private_handlers->param_loader->addYamlFile(_world_config_);
+    1639             :     }
+    1640             : 
+    1641          35 :     if (_network_config_ != "") {
+    1642          35 :       private_handlers->param_loader->addYamlFile(_network_config_);
+    1643             :     }
+    1644             : 
+    1645          35 :     bool success = false;
+    1646             : 
+    1647             :     try {
+    1648             : 
+    1649          35 :       ROS_INFO("[ControlManager]: initializing the controller '%s'", it->second.address.c_str());
+    1650          35 :       success = controller_list_[i]->initialize(ros::NodeHandle(nh_, it->second.name_space), common_handlers_, private_handlers);
+    1651             :     }
+    1652           0 :     catch (std::runtime_error& ex) {
+    1653           0 :       ROS_ERROR("[ControlManager]: exception caught during controller initialization: '%s'", ex.what());
+    1654             :     }
+    1655             : 
+    1656          35 :     if (!success) {
+    1657           0 :       ROS_ERROR("[ControlManager]: failed to initialize the controller '%s'", it->second.address.c_str());
+    1658           0 :       ros::shutdown();
+    1659             :     }
+    1660             :   }
+    1661             : 
+    1662           7 :   ROS_INFO("[ControlManager]: controllers were initialized");
+    1663             : 
+    1664             :   {
+    1665           7 :     auto idx = idxInVector(_failsafe_controller_name_, _controller_names_);
+    1666             : 
+    1667           7 :     if (idx) {
+    1668           7 :       _failsafe_controller_idx_ = idx.value();
+    1669             :     } else {
+    1670           0 :       ROS_ERROR("[ControlManager]: the failsafe controller (%s) is not within the loaded controllers", _failsafe_controller_name_.c_str());
+    1671           0 :       ros::shutdown();
+    1672             :     }
+    1673             :   }
+    1674             : 
+    1675             :   {
+    1676           7 :     auto idx = idxInVector(_eland_controller_name_, _controller_names_);
+    1677             : 
+    1678           7 :     if (idx) {
+    1679           7 :       _eland_controller_idx_ = idx.value();
+    1680             :     } else {
+    1681           0 :       ROS_ERROR("[ControlManager]: the eland controller (%s) is not within the loaded controllers", _eland_controller_name_.c_str());
+    1682           0 :       ros::shutdown();
+    1683             :     }
+    1684             :   }
+    1685             : 
+    1686             :   {
+    1687           7 :     auto idx = idxInVector(_joystick_controller_name_, _controller_names_);
+    1688             : 
+    1689           7 :     if (idx) {
+    1690           7 :       _joystick_controller_idx_ = idx.value();
+    1691             :     } else {
+    1692           0 :       ROS_ERROR("[ControlManager]: the joystick controller (%s) is not within the loaded controllers", _joystick_controller_name_.c_str());
+    1693           0 :       ros::shutdown();
+    1694             :     }
+    1695             :   }
+    1696             : 
+    1697           7 :   if (_bumper_switch_controller_) {
+    1698             : 
+    1699           7 :     auto idx = idxInVector(_bumper_controller_name_, _controller_names_);
+    1700             : 
+    1701           7 :     if (!idx) {
+    1702           0 :       ROS_ERROR("[ControlManager]: the bumper controller (%s) is not within the loaded controllers", _bumper_controller_name_.c_str());
+    1703           0 :       ros::shutdown();
+    1704             :     }
+    1705             :   }
+    1706             : 
+    1707             :   {
+    1708           7 :     auto idx = idxInVector(_joystick_fallback_controller_name_, _controller_names_);
+    1709             : 
+    1710           7 :     if (idx) {
+    1711           7 :       _joystick_fallback_controller_idx_ = idx.value();
+    1712             :     } else {
+    1713           0 :       ROS_ERROR("[ControlManager]: the joystick fallback controller (%s) is not within the loaded controllers", _joystick_fallback_controller_name_.c_str());
+    1714           0 :       ros::shutdown();
+    1715             :     }
+    1716             :   }
+    1717             : 
+    1718             :   // --------------------------------------------------------------
+    1719             :   // |                  activate the NullTracker                  |
+    1720             :   // --------------------------------------------------------------
+    1721             : 
+    1722           7 :   ROS_INFO("[ControlManager]: activating the null tracker");
+    1723             : 
+    1724           7 :   tracker_list_[_null_tracker_idx_]->activate(last_tracker_cmd_);
+    1725           7 :   active_tracker_idx_ = _null_tracker_idx_;
+    1726             : 
+    1727             :   // --------------------------------------------------------------
+    1728             :   // |    activate the eland controller as the first controller   |
+    1729             :   // --------------------------------------------------------------
+    1730             : 
+    1731           7 :   ROS_INFO("[ControlManager]: activating the the eland controller (%s) as the first controller", _controller_names_[_eland_controller_idx_].c_str());
+    1732             : 
+    1733           7 :   controller_list_[_eland_controller_idx_]->activate(last_control_output_);
+    1734           7 :   active_controller_idx_ = _eland_controller_idx_;
+    1735             : 
+    1736             :   // update the time
+    1737             :   {
+    1738          14 :     std::scoped_lock lock(mutex_controller_tracker_switch_time_);
+    1739             : 
+    1740           7 :     controller_tracker_switch_time_ = ros::Time::now();
+    1741             :   }
+    1742             : 
+    1743           7 :   output_enabled_ = false;
+    1744             : 
+    1745             :   // | --------------- set the default constraints -------------- |
+    1746             : 
+    1747           7 :   sanitized_constraints_ = current_constraints_;
+    1748           7 :   setConstraints(current_constraints_);
+    1749             : 
+    1750             :   // | ------------------------ profiler ------------------------ |
+    1751             : 
+    1752           7 :   profiler_ = mrs_lib::Profiler(nh_, "ControlManager", _profiler_enabled_);
+    1753             : 
+    1754             :   // | ----------------------- publishers ----------------------- |
+    1755             : 
+    1756           7 :   control_output_publisher_ = OutputPublisher(nh_);
+    1757             : 
+    1758           7 :   ph_controller_diagnostics_             = mrs_lib::PublisherHandler<mrs_msgs::ControllerDiagnostics>(nh_, "controller_diagnostics_out", 1);
+    1759           7 :   ph_tracker_cmd_                        = mrs_lib::PublisherHandler<mrs_msgs::TrackerCommand>(nh_, "tracker_cmd_out", 1);
+    1760           7 :   ph_mrs_odom_input_                     = mrs_lib::PublisherHandler<mrs_msgs::EstimatorInput>(nh_, "estimator_input_out", 1);
+    1761           7 :   ph_control_reference_odom_             = mrs_lib::PublisherHandler<nav_msgs::Odometry>(nh_, "control_reference_out", 1);
+    1762           7 :   ph_diagnostics_                        = mrs_lib::PublisherHandler<mrs_msgs::ControlManagerDiagnostics>(nh_, "diagnostics_out", 1);
+    1763           7 :   ph_offboard_on_                        = mrs_lib::PublisherHandler<std_msgs::Empty>(nh_, "offboard_on_out", 1);
+    1764           7 :   ph_tilt_error_                         = mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>(nh_, "tilt_error_out", 1);
+    1765           7 :   ph_mass_estimate_                      = mrs_lib::PublisherHandler<std_msgs::Float64>(nh_, "mass_estimate_out", 1, false, 10.0);
+    1766           7 :   ph_throttle_                           = mrs_lib::PublisherHandler<std_msgs::Float64>(nh_, "throttle_out", 1, false, 10.0);
+    1767           7 :   ph_thrust_                             = mrs_lib::PublisherHandler<std_msgs::Float64>(nh_, "thrust_out", 1, false, 100.0);
+    1768           7 :   ph_control_error_                      = mrs_lib::PublisherHandler<mrs_msgs::ControlError>(nh_, "control_error_out", 1);
+    1769           7 :   ph_safety_area_markers_                = mrs_lib::PublisherHandler<visualization_msgs::MarkerArray>(nh_, "safety_area_markers_out", 1, true, 1.0);
+    1770           7 :   ph_safety_area_coordinates_markers_    = mrs_lib::PublisherHandler<visualization_msgs::MarkerArray>(nh_, "safety_area_coordinates_markers_out", 1, true, 1.0);
+    1771           7 :   ph_disturbances_markers_               = mrs_lib::PublisherHandler<visualization_msgs::MarkerArray>(nh_, "disturbances_markers_out", 1, false, 10.0);
+    1772           7 :   ph_bumper_status_                      = mrs_lib::PublisherHandler<mrs_msgs::BumperStatus>(nh_, "bumper_status_out", 1);
+    1773           7 :   ph_current_constraints_                = mrs_lib::PublisherHandler<mrs_msgs::DynamicsConstraints>(nh_, "current_constraints_out", 1);
+    1774           7 :   ph_heading_                            = mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>(nh_, "heading_out", 1);
+    1775           7 :   ph_speed_                              = mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>(nh_, "speed_out", 1, false, 10.0);
+    1776           7 :   pub_debug_original_trajectory_poses_   = mrs_lib::PublisherHandler<geometry_msgs::PoseArray>(nh_, "trajectory_original/poses_out", 1, true);
+    1777           7 :   pub_debug_original_trajectory_markers_ = mrs_lib::PublisherHandler<visualization_msgs::MarkerArray>(nh_, "trajectory_original/markers_out", 1, true);
+    1778             : 
+    1779             :   // | ----------------------- subscribers ---------------------- |
+    1780             : 
+    1781          14 :   mrs_lib::SubscribeHandlerOptions shopts;
+    1782           7 :   shopts.nh                 = nh_;
+    1783           7 :   shopts.node_name          = "ControlManager";
+    1784           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+    1785           7 :   shopts.threadsafe         = true;
+    1786           7 :   shopts.autostart          = true;
+    1787           7 :   shopts.queue_size         = 10;
+    1788           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+    1789             : 
+    1790           7 :   if (_state_input_ == INPUT_UAV_STATE) {
+    1791           7 :     sh_uav_state_ = mrs_lib::SubscribeHandler<mrs_msgs::UavState>(shopts, "uav_state_in", &ControlManager::callbackUavState, this);
+    1792           0 :   } else if (_state_input_ == INPUT_ODOMETRY) {
+    1793           0 :     sh_odometry_ = mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, "odometry_in", &ControlManager::callbackOdometry, this);
+    1794             :   }
+    1795             : 
+    1796           7 :   if (_odometry_innovation_check_enabled_) {
+    1797           7 :     sh_odometry_innovation_ = mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, "odometry_innovation_in");
+    1798             :   }
+    1799             : 
+    1800           7 :   sh_bumper_    = mrs_lib::SubscribeHandler<mrs_msgs::ObstacleSectors>(shopts, "bumper_sectors_in");
+    1801           7 :   sh_max_z_     = mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped>(shopts, "max_z_in");
+    1802           7 :   sh_joystick_  = mrs_lib::SubscribeHandler<sensor_msgs::Joy>(shopts, "joystick_in", &ControlManager::callbackJoystick, this);
+    1803           7 :   sh_gnss_      = mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix>(shopts, "gnss_in", &ControlManager::callbackGNSS, this);
+    1804           7 :   sh_hw_api_rc_ = mrs_lib::SubscribeHandler<mrs_msgs::HwApiRcChannels>(shopts, "hw_api_rc_in", &ControlManager::callbackRC, this);
+    1805             : 
+    1806           7 :   sh_hw_api_status_ = mrs_lib::SubscribeHandler<mrs_msgs::HwApiStatus>(shopts, "hw_api_status_in", &ControlManager::callbackHwApiStatus, this);
+    1807             : 
+    1808             :   // | -------------------- general services -------------------- |
+    1809             : 
+    1810           7 :   service_server_switch_tracker_             = nh_.advertiseService("switch_tracker_in", &ControlManager::callbackSwitchTracker, this);
+    1811           7 :   service_server_switch_controller_          = nh_.advertiseService("switch_controller_in", &ControlManager::callbackSwitchController, this);
+    1812           7 :   service_server_reset_tracker_              = nh_.advertiseService("tracker_reset_static_in", &ControlManager::callbackTrackerResetStatic, this);
+    1813           7 :   service_server_hover_                      = nh_.advertiseService("hover_in", &ControlManager::callbackHover, this);
+    1814           7 :   service_server_ehover_                     = nh_.advertiseService("ehover_in", &ControlManager::callbackEHover, this);
+    1815           7 :   service_server_failsafe_                   = nh_.advertiseService("failsafe_in", &ControlManager::callbackFailsafe, this);
+    1816           7 :   service_server_failsafe_escalating_        = nh_.advertiseService("failsafe_escalating_in", &ControlManager::callbackFailsafeEscalating, this);
+    1817           7 :   service_server_toggle_output_              = nh_.advertiseService("toggle_output_in", &ControlManager::callbackToggleOutput, this);
+    1818           7 :   service_server_arm_                        = nh_.advertiseService("arm_in", &ControlManager::callbackArm, this);
+    1819           7 :   service_server_enable_callbacks_           = nh_.advertiseService("enable_callbacks_in", &ControlManager::callbackEnableCallbacks, this);
+    1820           7 :   service_server_set_constraints_            = nh_.advertiseService("set_constraints_in", &ControlManager::callbackSetConstraints, this);
+    1821           7 :   service_server_use_joystick_               = nh_.advertiseService("use_joystick_in", &ControlManager::callbackUseJoystick, this);
+    1822           7 :   service_server_use_safety_area_            = nh_.advertiseService("use_safety_area_in", &ControlManager::callbackUseSafetyArea, this);
+    1823           7 :   service_server_eland_                      = nh_.advertiseService("eland_in", &ControlManager::callbackEland, this);
+    1824           7 :   service_server_parachute_                  = nh_.advertiseService("parachute_in", &ControlManager::callbackParachute, this);
+    1825           7 :   service_server_transform_reference_        = nh_.advertiseService("transform_reference_in", &ControlManager::callbackTransformReference, this);
+    1826           7 :   service_server_transform_pose_             = nh_.advertiseService("transform_pose_in", &ControlManager::callbackTransformPose, this);
+    1827           7 :   service_server_transform_vector3_          = nh_.advertiseService("transform_vector3_in", &ControlManager::callbackTransformVector3, this);
+    1828           7 :   service_server_bumper_enabler_             = nh_.advertiseService("bumper_in", &ControlManager::callbackEnableBumper, this);
+    1829           7 :   service_server_get_min_z_                  = nh_.advertiseService("get_min_z_in", &ControlManager::callbackGetMinZ, this);
+    1830           7 :   service_server_validate_reference_         = nh_.advertiseService("validate_reference_in", &ControlManager::callbackValidateReference, this);
+    1831           7 :   service_server_validate_reference_2d_      = nh_.advertiseService("validate_reference_2d_in", &ControlManager::callbackValidateReference2d, this);
+    1832           7 :   service_server_validate_reference_list_    = nh_.advertiseService("validate_reference_list_in", &ControlManager::callbackValidateReferenceList, this);
+    1833           7 :   service_server_start_trajectory_tracking_  = nh_.advertiseService("start_trajectory_tracking_in", &ControlManager::callbackStartTrajectoryTracking, this);
+    1834           7 :   service_server_stop_trajectory_tracking_   = nh_.advertiseService("stop_trajectory_tracking_in", &ControlManager::callbackStopTrajectoryTracking, this);
+    1835           7 :   service_server_resume_trajectory_tracking_ = nh_.advertiseService("resume_trajectory_tracking_in", &ControlManager::callbackResumeTrajectoryTracking, this);
+    1836           7 :   service_server_goto_trajectory_start_      = nh_.advertiseService("goto_trajectory_start_in", &ControlManager::callbackGotoTrajectoryStart, this);
+    1837             : 
+    1838           7 :   sch_arming_                 = mrs_lib::ServiceClientHandler<std_srvs::SetBool>(nh_, "hw_api_arming_out");
+    1839           7 :   sch_eland_                  = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "eland_out");
+    1840           7 :   sch_shutdown_               = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "shutdown_out");
+    1841           7 :   sch_set_odometry_callbacks_ = mrs_lib::ServiceClientHandler<std_srvs::SetBool>(nh_, "set_odometry_callbacks_out");
+    1842           7 :   sch_ungrip_                 = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "ungrip_out");
+    1843           7 :   sch_parachute_              = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "parachute_out");
+    1844             : 
+    1845             :   // | ---------------- setpoint command services --------------- |
+    1846             : 
+    1847             :   // human callable
+    1848           7 :   service_server_goto_                 = nh_.advertiseService("goto_in", &ControlManager::callbackGoto, this);
+    1849           7 :   service_server_goto_fcu_             = nh_.advertiseService("goto_fcu_in", &ControlManager::callbackGotoFcu, this);
+    1850           7 :   service_server_goto_relative_        = nh_.advertiseService("goto_relative_in", &ControlManager::callbackGotoRelative, this);
+    1851           7 :   service_server_goto_altitude_        = nh_.advertiseService("goto_altitude_in", &ControlManager::callbackGotoAltitude, this);
+    1852           7 :   service_server_set_heading_          = nh_.advertiseService("set_heading_in", &ControlManager::callbackSetHeading, this);
+    1853           7 :   service_server_set_heading_relative_ = nh_.advertiseService("set_heading_relative_in", &ControlManager::callbackSetHeadingRelative, this);
+    1854             : 
+    1855           7 :   service_server_reference_ = nh_.advertiseService("reference_in", &ControlManager::callbackReferenceService, this);
+    1856           7 :   sh_reference_             = mrs_lib::SubscribeHandler<mrs_msgs::ReferenceStamped>(shopts, "reference_in", &ControlManager::callbackReferenceTopic, this);
+    1857             : 
+    1858           7 :   service_server_velocity_reference_ = nh_.advertiseService("velocity_reference_in", &ControlManager::callbackVelocityReferenceService, this);
+    1859             :   sh_velocity_reference_ =
+    1860           7 :       mrs_lib::SubscribeHandler<mrs_msgs::VelocityReferenceStamped>(shopts, "velocity_reference_in", &ControlManager::callbackVelocityReferenceTopic, this);
+    1861             : 
+    1862           7 :   service_server_trajectory_reference_ = nh_.advertiseService("trajectory_reference_in", &ControlManager::callbackTrajectoryReferenceService, this);
+    1863             :   sh_trajectory_reference_ =
+    1864           7 :       mrs_lib::SubscribeHandler<mrs_msgs::TrajectoryReference>(shopts, "trajectory_reference_in", &ControlManager::callbackTrajectoryReferenceTopic, this);
+    1865             : 
+    1866             :   // | --------------------- other services --------------------- |
+    1867             : 
+    1868           7 :   service_server_emergency_reference_ = nh_.advertiseService("emergency_reference_in", &ControlManager::callbackEmergencyReference, this);
+    1869           7 :   service_server_pirouette_           = nh_.advertiseService("pirouette_in", &ControlManager::callbackPirouette, this);
+    1870             : 
+    1871             :   // | ------------------------- timers ------------------------- |
+    1872             : 
+    1873           7 :   timer_status_    = nh_.createTimer(ros::Rate(_status_timer_rate_), &ControlManager::timerStatus, this);
+    1874           7 :   timer_safety_    = nh_.createTimer(ros::Rate(_safety_timer_rate_), &ControlManager::timerSafety, this);
+    1875           7 :   timer_bumper_    = nh_.createTimer(ros::Rate(_bumper_timer_rate_), &ControlManager::timerBumper, this, false, bumper_enabled_);
+    1876           7 :   timer_eland_     = nh_.createTimer(ros::Rate(_elanding_timer_rate_), &ControlManager::timerEland, this, false, false);
+    1877           7 :   timer_failsafe_  = nh_.createTimer(ros::Rate(_failsafe_timer_rate_), &ControlManager::timerFailsafe, this, false, false);
+    1878           7 :   timer_pirouette_ = nh_.createTimer(ros::Rate(_pirouette_timer_rate_), &ControlManager::timerPirouette, this, false, false);
+    1879           7 :   timer_joystick_  = nh_.createTimer(ros::Rate(_joystick_timer_rate_), &ControlManager::timerJoystick, this);
+    1880             : 
+    1881             :   // | ----------------------- finish init ---------------------- |
+    1882             : 
+    1883           7 :   if (!param_loader.loadedSuccessfully()) {
+    1884           0 :     ROS_ERROR("[ControlManager]: could not load all parameters!");
+    1885           0 :     ros::shutdown();
+    1886             :   }
+    1887             : 
+    1888           7 :   is_initialized_ = true;
+    1889             : 
+    1890           7 :   ROS_INFO("[ControlManager]: initialized");
+    1891           7 : }
+    1892             : 
+    1893             : //}
+    1894             : 
+    1895             : // --------------------------------------------------------------
+    1896             : // |                           timers                           |
+    1897             : // --------------------------------------------------------------
+    1898             : 
+    1899             : /* timerHwApiCapabilities() //{ */
+    1900             : 
+    1901          10 : void ControlManager::timerHwApiCapabilities(const ros::TimerEvent& event) {
+    1902             : 
+    1903          20 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerHwApiCapabilities", _status_timer_rate_, 1.0, event);
+    1904          20 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerHwApiCapabilities", scope_timer_logger_, scope_timer_enabled_);
+    1905             : 
+    1906          10 :   if (!sh_hw_api_capabilities_.hasMsg()) {
+    1907           3 :     ROS_INFO_THROTTLE(1.0, "[ControlManager]: waiting for HW API capabilities");
+    1908           3 :     return;
+    1909             :   }
+    1910             : 
+    1911          14 :   auto hw_ap_capabilities = sh_hw_api_capabilities_.getMsg();
+    1912             : 
+    1913           7 :   ROS_INFO("[ControlManager]: got HW API capabilities, the possible control modes are:");
+    1914             : 
+    1915           7 :   if (hw_ap_capabilities->accepts_actuator_cmd) {
+    1916           0 :     ROS_INFO("[ControlManager]: - actuator command");
+    1917           0 :     _hw_api_inputs_.actuators = true;
+    1918             :   }
+    1919             : 
+    1920           7 :   if (hw_ap_capabilities->accepts_control_group_cmd) {
+    1921           0 :     ROS_INFO("[ControlManager]: - control group command");
+    1922           0 :     _hw_api_inputs_.control_group = true;
+    1923             :   }
+    1924             : 
+    1925           7 :   if (hw_ap_capabilities->accepts_attitude_rate_cmd) {
+    1926           7 :     ROS_INFO("[ControlManager]: - attitude rate command");
+    1927           7 :     _hw_api_inputs_.attitude_rate = true;
+    1928             :   }
+    1929             : 
+    1930           7 :   if (hw_ap_capabilities->accepts_attitude_cmd) {
+    1931           7 :     ROS_INFO("[ControlManager]: - attitude command");
+    1932           7 :     _hw_api_inputs_.attitude = true;
+    1933             :   }
+    1934             : 
+    1935           7 :   if (hw_ap_capabilities->accepts_acceleration_hdg_rate_cmd) {
+    1936           0 :     ROS_INFO("[ControlManager]: - acceleration+hdg rate command");
+    1937           0 :     _hw_api_inputs_.acceleration_hdg_rate = true;
+    1938             :   }
+    1939             : 
+    1940           7 :   if (hw_ap_capabilities->accepts_acceleration_hdg_cmd) {
+    1941           0 :     ROS_INFO("[ControlManager]: - acceleration+hdg command");
+    1942           0 :     _hw_api_inputs_.acceleration_hdg = true;
+    1943             :   }
+    1944             : 
+    1945           7 :   if (hw_ap_capabilities->accepts_velocity_hdg_rate_cmd) {
+    1946           0 :     ROS_INFO("[ControlManager]: - velocityhdg rate command");
+    1947           0 :     _hw_api_inputs_.velocity_hdg_rate = true;
+    1948             :   }
+    1949             : 
+    1950           7 :   if (hw_ap_capabilities->accepts_velocity_hdg_cmd) {
+    1951           0 :     ROS_INFO("[ControlManager]: - velocityhdg command");
+    1952           0 :     _hw_api_inputs_.velocity_hdg = true;
+    1953             :   }
+    1954             : 
+    1955           7 :   if (hw_ap_capabilities->accepts_position_cmd) {
+    1956           0 :     ROS_INFO("[ControlManager]: - position command");
+    1957           0 :     _hw_api_inputs_.position = true;
+    1958             :   }
+    1959             : 
+    1960           7 :   initialize();
+    1961             : 
+    1962           7 :   timer_hw_api_capabilities_.stop();
+    1963             : }
+    1964             : 
+    1965             : //}
+    1966             : 
+    1967             : /* //{ timerStatus() */
+    1968             : 
+    1969        1080 : void ControlManager::timerStatus(const ros::TimerEvent& event) {
+    1970             : 
+    1971        1080 :   if (!is_initialized_)
+    1972           0 :     return;
+    1973             : 
+    1974        3240 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerStatus", _status_timer_rate_, 0.1, event);
+    1975        3240 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerStatus", scope_timer_logger_, scope_timer_enabled_);
+    1976             : 
+    1977             :   // copy member variables
+    1978        2160 :   auto uav_state             = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    1979        2160 :   auto last_control_output   = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    1980        2160 :   auto last_tracker_cmd      = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    1981        1080 :   auto yaw_error             = mrs_lib::get_mutexed(mutex_attitude_error_, yaw_error_);
+    1982        1080 :   auto position_error        = mrs_lib::get_mutexed(mutex_position_error_, position_error_);
+    1983        1080 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    1984        1080 :   auto active_tracker_idx    = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    1985             : 
+    1986             :   double uav_x, uav_y, uav_z;
+    1987        1080 :   uav_x = uav_state.pose.position.x;
+    1988        1080 :   uav_y = uav_state.pose.position.y;
+    1989        1080 :   uav_z = uav_state.pose.position.z;
+    1990             : 
+    1991             :   // --------------------------------------------------------------
+    1992             :   // |                      print the status                      |
+    1993             :   // --------------------------------------------------------------
+    1994             : 
+    1995             :   {
+    1996        2160 :     std::string controller = _controller_names_[active_controller_idx];
+    1997        2160 :     std::string tracker    = _tracker_names_[active_tracker_idx];
+    1998        1080 :     double      mass       = last_control_output.diagnostics.total_mass;
+    1999        1080 :     double      bx_b       = last_control_output.diagnostics.disturbance_bx_b;
+    2000        1080 :     double      by_b       = last_control_output.diagnostics.disturbance_by_b;
+    2001        1080 :     double      wx_w       = last_control_output.diagnostics.disturbance_wx_w;
+    2002        1080 :     double      wy_w       = last_control_output.diagnostics.disturbance_wy_w;
+    2003             : 
+    2004        1080 :     ROS_INFO_THROTTLE(5.0, "[ControlManager]: tracker: '%s', controller: '%s', mass: '%.2f kg', disturbances: body [%.2f, %.2f] N, world [%.2f, %.2f] N",
+    2005             :                       tracker.c_str(), controller.c_str(), mass, bx_b, by_b, wx_w, wy_w);
+    2006             :   }
+    2007             : 
+    2008             :   // --------------------------------------------------------------
+    2009             :   // |                   publish the diagnostics                  |
+    2010             :   // --------------------------------------------------------------
+    2011             : 
+    2012        1080 :   publishDiagnostics();
+    2013             : 
+    2014             :   // --------------------------------------------------------------
+    2015             :   // |                publish if the offboard is on               |
+    2016             :   // --------------------------------------------------------------
+    2017             : 
+    2018        1080 :   if (offboard_mode_) {
+    2019             : 
+    2020         804 :     std_msgs::Empty offboard_on_out;
+    2021             : 
+    2022         804 :     ph_offboard_on_.publish(offboard_on_out);
+    2023             :   }
+    2024             : 
+    2025             :   // --------------------------------------------------------------
+    2026             :   // |                   publish the tilt error                   |
+    2027             :   // --------------------------------------------------------------
+    2028             :   {
+    2029        2160 :     std::scoped_lock lock(mutex_attitude_error_);
+    2030             : 
+    2031        1080 :     if (tilt_error_) {
+    2032             : 
+    2033        2160 :       mrs_msgs::Float64Stamped tilt_error_out;
+    2034        1080 :       tilt_error_out.header.stamp    = ros::Time::now();
+    2035        1080 :       tilt_error_out.header.frame_id = uav_state.header.frame_id;
+    2036        1080 :       tilt_error_out.value           = (180.0 / M_PI) * tilt_error_.value();
+    2037             : 
+    2038        1080 :       ph_tilt_error_.publish(tilt_error_out);
+    2039             :     }
+    2040             :   }
+    2041             : 
+    2042             :   // --------------------------------------------------------------
+    2043             :   // |                  publish the control error                 |
+    2044             :   // --------------------------------------------------------------
+    2045             : 
+    2046        1080 :   if (position_error) {
+    2047             : 
+    2048         753 :     Eigen::Vector3d pos_error_value = position_error.value();
+    2049             : 
+    2050        1506 :     mrs_msgs::ControlError msg_out;
+    2051             : 
+    2052         753 :     msg_out.header.stamp    = ros::Time::now();
+    2053         753 :     msg_out.header.frame_id = uav_state.header.frame_id;
+    2054             : 
+    2055         753 :     msg_out.position_errors.x    = pos_error_value[0];
+    2056         753 :     msg_out.position_errors.y    = pos_error_value[1];
+    2057         753 :     msg_out.position_errors.z    = pos_error_value[2];
+    2058         753 :     msg_out.total_position_error = pos_error_value.norm();
+    2059             : 
+    2060         753 :     if (yaw_error_) {
+    2061         753 :       msg_out.yaw_error = yaw_error.value();
+    2062             :     }
+    2063             : 
+    2064         753 :     std::map<std::string, ControllerParams>::iterator it;
+    2065             : 
+    2066         753 :     it = controllers_.find(_controller_names_[active_controller_idx]);
+    2067             : 
+    2068         753 :     msg_out.position_eland_threshold    = it->second.eland_threshold;
+    2069         753 :     msg_out.position_failsafe_threshold = it->second.failsafe_threshold;
+    2070             : 
+    2071         753 :     ph_control_error_.publish(msg_out);
+    2072             :   }
+    2073             : 
+    2074             :   // --------------------------------------------------------------
+    2075             :   // |                  publish the mass estimate                 |
+    2076             :   // --------------------------------------------------------------
+    2077             : 
+    2078        1080 :   if (last_control_output.diagnostics.mass_estimator) {
+    2079             : 
+    2080         593 :     std_msgs::Float64 mass_estimate_out;
+    2081         593 :     mass_estimate_out.data = _uav_mass_ + last_control_output.diagnostics.mass_difference;
+    2082             : 
+    2083         593 :     ph_mass_estimate_.publish(mass_estimate_out);
+    2084             :   }
+    2085             : 
+    2086             :   // --------------------------------------------------------------
+    2087             :   // |                 publish the current heading                |
+    2088             :   // --------------------------------------------------------------
+    2089             : 
+    2090        1080 :   if (_state_input_ == INPUT_UAV_STATE && sh_uav_state_.hasMsg()) {
+    2091             : 
+    2092             :     try {
+    2093             : 
+    2094             :       double heading;
+    2095             : 
+    2096         895 :       heading = mrs_lib::AttitudeConverter(uav_state.pose.orientation).getHeading();
+    2097             : 
+    2098        1790 :       mrs_msgs::Float64Stamped heading_out;
+    2099         895 :       heading_out.header = uav_state.header;
+    2100         895 :       heading_out.value  = heading;
+    2101             : 
+    2102         895 :       ph_heading_.publish(heading_out);
+    2103             :     }
+    2104           0 :     catch (...) {
+    2105           0 :       ROS_ERROR_THROTTLE(1.0, "exception caught, could not transform heading");
+    2106             :     }
+    2107             :   }
+    2108             : 
+    2109             :   // --------------------------------------------------------------
+    2110             :   // |                  publish the current speed                 |
+    2111             :   // --------------------------------------------------------------
+    2112             : 
+    2113        1080 :   if (_state_input_ == INPUT_UAV_STATE && sh_uav_state_.hasMsg()) {
+    2114             : 
+    2115         895 :     double speed = sqrt(pow(uav_state.velocity.linear.x, 2) + pow(uav_state.velocity.linear.y, 2) + pow(uav_state.velocity.linear.z, 2));
+    2116             : 
+    2117        1790 :     mrs_msgs::Float64Stamped speed_out;
+    2118         895 :     speed_out.header = uav_state.header;
+    2119         895 :     speed_out.value  = speed;
+    2120             : 
+    2121         895 :     ph_speed_.publish(speed_out);
+    2122             :   }
+    2123             : 
+    2124             :   // --------------------------------------------------------------
+    2125             :   // |               publish the safety area markers              |
+    2126             :   // --------------------------------------------------------------
+    2127             : 
+    2128        1080 :   if (use_safety_area_) {
+    2129             : 
+    2130        1244 :     mrs_msgs::ReferenceStamped temp_ref;
+    2131         622 :     temp_ref.header.frame_id = _safety_area_horizontal_frame_;
+    2132             : 
+    2133        1244 :     geometry_msgs::TransformStamped tf;
+    2134             : 
+    2135        1866 :     auto ret = transformer_->getTransform(_safety_area_horizontal_frame_, "local_origin", ros::Time(0));
+    2136             : 
+    2137         622 :     if (ret) {
+    2138             : 
+    2139         479 :       ROS_INFO_ONCE("[ControlManager]: got TFs, publishing safety area markers");
+    2140             : 
+    2141         958 :       visualization_msgs::MarkerArray safety_area_marker_array;
+    2142         958 :       visualization_msgs::MarkerArray safety_area_coordinates_marker_array;
+    2143             : 
+    2144         958 :       mrs_lib::Polygon border = safety_zone_->getBorder();
+    2145             : 
+    2146         958 :       std::vector<geometry_msgs::Point> border_points_bot_original = border.getPointMessageVector(getMinZ(_safety_area_horizontal_frame_));
+    2147         958 :       std::vector<geometry_msgs::Point> border_points_top_original = border.getPointMessageVector(getMaxZ(_safety_area_horizontal_frame_));
+    2148             : 
+    2149         958 :       std::vector<geometry_msgs::Point> border_points_bot_transformed = border_points_bot_original;
+    2150         958 :       std::vector<geometry_msgs::Point> border_points_top_transformed = border_points_bot_original;
+    2151             : 
+    2152             :       // if we fail in transforming the area at some point
+    2153             :       // do not publish it at all
+    2154         479 :       bool tf_success = true;
+    2155             : 
+    2156         958 :       geometry_msgs::TransformStamped tf = ret.value();
+    2157             : 
+    2158             :       /* transform area points to local origin //{ */
+    2159             : 
+    2160             :       // transform border bottom points to local origin
+    2161        2395 :       for (size_t i = 0; i < border_points_bot_original.size(); i++) {
+    2162             : 
+    2163        1916 :         temp_ref.header.frame_id      = _safety_area_horizontal_frame_;
+    2164        1916 :         temp_ref.header.stamp         = ros::Time(0);
+    2165        1916 :         temp_ref.reference.position.x = border_points_bot_original[i].x;
+    2166        1916 :         temp_ref.reference.position.y = border_points_bot_original[i].y;
+    2167        1916 :         temp_ref.reference.position.z = border_points_bot_original[i].z;
+    2168             : 
+    2169        3832 :         if (auto ret = transformer_->transform(temp_ref, tf)) {
+    2170             : 
+    2171        1916 :           temp_ref = ret.value();
+    2172             : 
+    2173        1916 :           border_points_bot_transformed[i].x = temp_ref.reference.position.x;
+    2174        1916 :           border_points_bot_transformed[i].y = temp_ref.reference.position.y;
+    2175        1916 :           border_points_bot_transformed[i].z = temp_ref.reference.position.z;
+    2176             : 
+    2177             :         } else {
+    2178           0 :           tf_success = false;
+    2179             :         }
+    2180             :       }
+    2181             : 
+    2182             :       // transform border top points to local origin
+    2183        2395 :       for (size_t i = 0; i < border_points_top_original.size(); i++) {
+    2184             : 
+    2185        1916 :         temp_ref.header.frame_id      = _safety_area_horizontal_frame_;
+    2186        1916 :         temp_ref.header.stamp         = ros::Time(0);
+    2187        1916 :         temp_ref.reference.position.x = border_points_top_original[i].x;
+    2188        1916 :         temp_ref.reference.position.y = border_points_top_original[i].y;
+    2189        1916 :         temp_ref.reference.position.z = border_points_top_original[i].z;
+    2190             : 
+    2191        3832 :         if (auto ret = transformer_->transform(temp_ref, tf)) {
+    2192             : 
+    2193        1916 :           temp_ref = ret.value();
+    2194             : 
+    2195        1916 :           border_points_top_transformed[i].x = temp_ref.reference.position.x;
+    2196        1916 :           border_points_top_transformed[i].y = temp_ref.reference.position.y;
+    2197        1916 :           border_points_top_transformed[i].z = temp_ref.reference.position.z;
+    2198             : 
+    2199             :         } else {
+    2200           0 :           tf_success = false;
+    2201             :         }
+    2202             :       }
+    2203             : 
+    2204             :       //}
+    2205             : 
+    2206         958 :       visualization_msgs::Marker safety_area_marker;
+    2207             : 
+    2208         479 :       safety_area_marker.header.frame_id = _uav_name_ + "/local_origin";
+    2209         479 :       safety_area_marker.type            = visualization_msgs::Marker::LINE_LIST;
+    2210         479 :       safety_area_marker.color.a         = 0.15;
+    2211         479 :       safety_area_marker.scale.x         = 0.2;
+    2212         479 :       safety_area_marker.color.r         = 1;
+    2213         479 :       safety_area_marker.color.g         = 0;
+    2214         479 :       safety_area_marker.color.b         = 0;
+    2215             : 
+    2216         479 :       safety_area_marker.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+    2217             : 
+    2218         958 :       visualization_msgs::Marker safety_area_coordinates_marker;
+    2219             : 
+    2220         479 :       safety_area_coordinates_marker.header.frame_id = _uav_name_ + "/local_origin";
+    2221         479 :       safety_area_coordinates_marker.type            = visualization_msgs::Marker::TEXT_VIEW_FACING;
+    2222         479 :       safety_area_coordinates_marker.color.a         = 1;
+    2223         479 :       safety_area_coordinates_marker.scale.z         = 1.0;
+    2224         479 :       safety_area_coordinates_marker.color.r         = 0;
+    2225         479 :       safety_area_coordinates_marker.color.g         = 0;
+    2226         479 :       safety_area_coordinates_marker.color.b         = 0;
+    2227             : 
+    2228         479 :       safety_area_coordinates_marker.id = 0;
+    2229             : 
+    2230         479 :       safety_area_coordinates_marker.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+    2231             : 
+    2232             :       /* adding safety area points //{ */
+    2233             : 
+    2234             :       // bottom border
+    2235        2395 :       for (size_t i = 0; i < border_points_bot_transformed.size(); i++) {
+    2236             : 
+    2237        1916 :         safety_area_marker.points.push_back(border_points_bot_transformed[i]);
+    2238        1916 :         safety_area_marker.points.push_back(border_points_bot_transformed[(i + 1) % border_points_bot_transformed.size()]);
+    2239             : 
+    2240        3832 :         std::stringstream ss;
+    2241             : 
+    2242        1916 :         if (_safety_area_horizontal_frame_ == "latlon_origin") {
+    2243           0 :           ss << "idx: " << i << std::endl
+    2244           0 :              << std::setprecision(6) << std::fixed << "lat: " << border_points_bot_original[i].x << std::endl
+    2245           0 :              << "lon: " << border_points_bot_original[i].y;
+    2246             :         } else {
+    2247        1916 :           ss << "idx: " << i << std::endl
+    2248        1916 :              << std::setprecision(1) << std::fixed << "x: " << border_points_bot_original[i].x << std::endl
+    2249        1916 :              << "y: " << border_points_bot_original[i].y;
+    2250             :         }
+    2251             : 
+    2252        1916 :         safety_area_coordinates_marker.color.r = 0;
+    2253        1916 :         safety_area_coordinates_marker.color.g = 0;
+    2254        1916 :         safety_area_coordinates_marker.color.b = 0;
+    2255             : 
+    2256        1916 :         safety_area_coordinates_marker.pose.position = border_points_bot_transformed[i];
+    2257        1916 :         safety_area_coordinates_marker.text          = ss.str();
+    2258        1916 :         safety_area_coordinates_marker.id++;
+    2259             : 
+    2260        1916 :         safety_area_coordinates_marker_array.markers.push_back(safety_area_coordinates_marker);
+    2261             :       }
+    2262             : 
+    2263             :       // top border + top/bot edges
+    2264        2395 :       for (size_t i = 0; i < border_points_top_transformed.size(); i++) {
+    2265             : 
+    2266        1916 :         safety_area_marker.points.push_back(border_points_top_transformed[i]);
+    2267        1916 :         safety_area_marker.points.push_back(border_points_top_transformed[(i + 1) % border_points_top_transformed.size()]);
+    2268             : 
+    2269        1916 :         safety_area_marker.points.push_back(border_points_bot_transformed[i]);
+    2270        1916 :         safety_area_marker.points.push_back(border_points_top_transformed[i]);
+    2271             : 
+    2272        3832 :         std::stringstream ss;
+    2273             : 
+    2274        1916 :         if (_safety_area_horizontal_frame_ == "latlon_origin") {
+    2275           0 :           ss << "idx: " << i << std::endl
+    2276           0 :              << std::setprecision(6) << std::fixed << "lat: " << border_points_bot_original[i].x << std::endl
+    2277           0 :              << "lon: " << border_points_bot_original[i].y;
+    2278             :         } else {
+    2279        1916 :           ss << "idx: " << i << std::endl
+    2280        1916 :              << std::setprecision(1) << std::fixed << "x: " << border_points_bot_original[i].x << std::endl
+    2281        1916 :              << "y: " << border_points_bot_original[i].y;
+    2282             :         }
+    2283             : 
+    2284        1916 :         safety_area_coordinates_marker.color.r = 1;
+    2285        1916 :         safety_area_coordinates_marker.color.g = 1;
+    2286        1916 :         safety_area_coordinates_marker.color.b = 1;
+    2287             : 
+    2288        1916 :         safety_area_coordinates_marker.pose.position = border_points_top_transformed[i];
+    2289        1916 :         safety_area_coordinates_marker.text          = ss.str();
+    2290        1916 :         safety_area_coordinates_marker.id++;
+    2291             : 
+    2292        1916 :         safety_area_coordinates_marker_array.markers.push_back(safety_area_coordinates_marker);
+    2293             :       }
+    2294             : 
+    2295             :       //}
+    2296             : 
+    2297         479 :       if (tf_success) {
+    2298             : 
+    2299         479 :         safety_area_marker_array.markers.push_back(safety_area_marker);
+    2300             : 
+    2301         479 :         ph_safety_area_markers_.publish(safety_area_marker_array);
+    2302             : 
+    2303         479 :         ph_safety_area_coordinates_markers_.publish(safety_area_coordinates_marker_array);
+    2304             :       }
+    2305             : 
+    2306             :     } else {
+    2307         143 :       ROS_WARN_ONCE("[ControlManager]: missing TFs, can not publish safety area markers");
+    2308             :     }
+    2309             :   }
+    2310             : 
+    2311             :   // --------------------------------------------------------------
+    2312             :   // |              publish the disturbances markers              |
+    2313             :   // --------------------------------------------------------------
+    2314             : 
+    2315        1080 :   if (last_control_output.diagnostics.disturbance_estimator && got_uav_state_) {
+    2316             : 
+    2317        1186 :     visualization_msgs::MarkerArray msg_out;
+    2318             : 
+    2319         593 :     double id = 0;
+    2320             : 
+    2321         593 :     double multiplier = 1.0;
+    2322             : 
+    2323         593 :     Eigen::Quaterniond quat_eigen = mrs_lib::AttitudeConverter(uav_state.pose.orientation);
+    2324             : 
+    2325         593 :     Eigen::Vector3d      vec3d;
+    2326         593 :     geometry_msgs::Point point;
+    2327             : 
+    2328             :     /* world disturbance //{ */
+    2329             :     {
+    2330             : 
+    2331        1186 :       visualization_msgs::Marker marker;
+    2332             : 
+    2333         593 :       marker.header.frame_id = uav_state.header.frame_id;
+    2334         593 :       marker.header.stamp    = ros::Time::now();
+    2335         593 :       marker.ns              = "control_manager";
+    2336         593 :       marker.id              = id++;
+    2337         593 :       marker.type            = visualization_msgs::Marker::ARROW;
+    2338         593 :       marker.action          = visualization_msgs::Marker::ADD;
+    2339             : 
+    2340             :       /* position //{ */
+    2341             : 
+    2342         593 :       marker.pose.position.x = 0.0;
+    2343         593 :       marker.pose.position.y = 0.0;
+    2344         593 :       marker.pose.position.z = 0.0;
+    2345             : 
+    2346             :       //}
+    2347             : 
+    2348             :       /* orientation //{ */
+    2349             : 
+    2350         593 :       marker.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+    2351             : 
+    2352             :       //}
+    2353             : 
+    2354             :       /* origin //{ */
+    2355         593 :       point.x = uav_x;
+    2356         593 :       point.y = uav_y;
+    2357         593 :       point.z = uav_z;
+    2358             : 
+    2359         593 :       marker.points.push_back(point);
+    2360             : 
+    2361             :       //}
+    2362             : 
+    2363             :       /* tip //{ */
+    2364             : 
+    2365         593 :       point.x = uav_x + multiplier * last_control_output.diagnostics.disturbance_wx_w;
+    2366         593 :       point.y = uav_y + multiplier * last_control_output.diagnostics.disturbance_wy_w;
+    2367         593 :       point.z = uav_z;
+    2368             : 
+    2369         593 :       marker.points.push_back(point);
+    2370             : 
+    2371             :       //}
+    2372             : 
+    2373         593 :       marker.scale.x = 0.05;
+    2374         593 :       marker.scale.y = 0.05;
+    2375         593 :       marker.scale.z = 0.05;
+    2376             : 
+    2377         593 :       marker.color.a = 0.5;
+    2378         593 :       marker.color.r = 1.0;
+    2379         593 :       marker.color.g = 0.0;
+    2380         593 :       marker.color.b = 0.0;
+    2381             : 
+    2382         593 :       marker.mesh_resource = "package://pr2_description/meshes/base_v0/base.dae";
+    2383             : 
+    2384         593 :       msg_out.markers.push_back(marker);
+    2385             :     }
+    2386             : 
+    2387             :     //}
+    2388             : 
+    2389             :     /* body disturbance //{ */
+    2390             :     {
+    2391             : 
+    2392        1186 :       visualization_msgs::Marker marker;
+    2393             : 
+    2394         593 :       marker.header.frame_id = uav_state.header.frame_id;
+    2395         593 :       marker.header.stamp    = ros::Time::now();
+    2396         593 :       marker.ns              = "control_manager";
+    2397         593 :       marker.id              = id++;
+    2398         593 :       marker.type            = visualization_msgs::Marker::ARROW;
+    2399         593 :       marker.action          = visualization_msgs::Marker::ADD;
+    2400             : 
+    2401             :       /* position //{ */
+    2402             : 
+    2403         593 :       marker.pose.position.x = 0.0;
+    2404         593 :       marker.pose.position.y = 0.0;
+    2405         593 :       marker.pose.position.z = 0.0;
+    2406             : 
+    2407             :       //}
+    2408             : 
+    2409             :       /* orientation //{ */
+    2410             : 
+    2411         593 :       marker.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+    2412             : 
+    2413             :       //}
+    2414             : 
+    2415             :       /* origin //{ */
+    2416             : 
+    2417         593 :       point.x = uav_x;
+    2418         593 :       point.y = uav_y;
+    2419         593 :       point.z = uav_z;
+    2420             : 
+    2421         593 :       marker.points.push_back(point);
+    2422             : 
+    2423             :       //}
+    2424             : 
+    2425             :       /* tip //{ */
+    2426             : 
+    2427         593 :       vec3d << multiplier * last_control_output.diagnostics.disturbance_bx_b, multiplier * last_control_output.diagnostics.disturbance_by_b, 0;
+    2428         593 :       vec3d = quat_eigen * vec3d;
+    2429             : 
+    2430         593 :       point.x = uav_x + vec3d[0];
+    2431         593 :       point.y = uav_y + vec3d[1];
+    2432         593 :       point.z = uav_z + vec3d[2];
+    2433             : 
+    2434         593 :       marker.points.push_back(point);
+    2435             : 
+    2436             :       //}
+    2437             : 
+    2438         593 :       marker.scale.x = 0.05;
+    2439         593 :       marker.scale.y = 0.05;
+    2440         593 :       marker.scale.z = 0.05;
+    2441             : 
+    2442         593 :       marker.color.a = 0.5;
+    2443         593 :       marker.color.r = 0.0;
+    2444         593 :       marker.color.g = 1.0;
+    2445         593 :       marker.color.b = 0.0;
+    2446             : 
+    2447         593 :       marker.mesh_resource = "package://pr2_description/meshes/base_v0/base.dae";
+    2448             : 
+    2449         593 :       msg_out.markers.push_back(marker);
+    2450             :     }
+    2451             : 
+    2452             :     //}
+    2453             : 
+    2454         593 :     ph_disturbances_markers_.publish(msg_out);
+    2455             :   }
+    2456             : 
+    2457             :   // --------------------------------------------------------------
+    2458             :   // |               publish the current constraints              |
+    2459             :   // --------------------------------------------------------------
+    2460             : 
+    2461        1080 :   if (got_constraints_) {
+    2462             : 
+    2463         891 :     auto sanitized_constraints = mrs_lib::get_mutexed(mutex_constraints_, sanitized_constraints_);
+    2464             : 
+    2465         891 :     mrs_msgs::DynamicsConstraints constraints = sanitized_constraints.constraints;
+    2466             : 
+    2467         891 :     ph_current_constraints_.publish(constraints);
+    2468             :   }
+    2469             : }
+    2470             : 
+    2471             : //}
+    2472             : 
+    2473             : /* //{ timerSafety() */
+    2474             : 
+    2475       17665 : void ControlManager::timerSafety(const ros::TimerEvent& event) {
+    2476             : 
+    2477       17665 :   mrs_lib::AtomicScopeFlag unset_running(running_safety_timer_);
+    2478             : 
+    2479       17665 :   if (!is_initialized_)
+    2480           0 :     return;
+    2481             : 
+    2482       35330 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerSafety", _safety_timer_rate_, 0.05, event);
+    2483       35330 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerSafety", scope_timer_logger_, scope_timer_enabled_);
+    2484             : 
+    2485             :   // copy member variables
+    2486       17665 :   auto last_control_output   = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    2487       17665 :   auto last_tracker_cmd      = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    2488       17665 :   auto [uav_state, uav_yaw]  = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_, uav_yaw_);
+    2489       17665 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    2490       17665 :   auto active_tracker_idx    = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    2491             : 
+    2492       33445 :   if (!got_uav_state_ || (_state_input_ == INPUT_UAV_STATE && _odometry_innovation_check_enabled_ && !sh_odometry_innovation_.hasMsg()) ||
+    2493       15780 :       active_tracker_idx == _null_tracker_idx_) {
+    2494        4847 :     return;
+    2495             :   }
+    2496             : 
+    2497       12818 :   if (odometry_switch_in_progress_) {
+    2498           0 :     ROS_WARN("[ControlManager]: timerSafety tried to run while odometry switch in progress");
+    2499           0 :     return;
+    2500             :   }
+    2501             : 
+    2502             :   // | ------------------------ timeouts ------------------------ |
+    2503             : 
+    2504       12818 :   if (_state_input_ == INPUT_UAV_STATE && sh_uav_state_.hasMsg()) {
+    2505       12818 :     double missing_for = (ros::Time::now() - sh_uav_state_.lastMsgTime()).toSec();
+    2506             : 
+    2507       12818 :     if (missing_for > _uav_state_max_missing_time_) {
+    2508           0 :       timeoutUavState(missing_for);
+    2509             :     }
+    2510             :   }
+    2511             : 
+    2512       12818 :   if (_state_input_ == INPUT_ODOMETRY && sh_odometry_.hasMsg()) {
+    2513           0 :     double missing_for = (ros::Time::now() - sh_odometry_.lastMsgTime()).toSec();
+    2514             : 
+    2515           0 :     if (missing_for > _uav_state_max_missing_time_) {
+    2516           0 :       timeoutUavState(missing_for);
+    2517             :     }
+    2518             :   }
+    2519             : 
+    2520             :   // | -------------- eland and failsafe thresholds ------------- |
+    2521             : 
+    2522       12818 :   std::map<std::string, ControllerParams>::iterator it;
+    2523       12818 :   it = controllers_.find(_controller_names_[active_controller_idx]);
+    2524             : 
+    2525       12818 :   _eland_threshold_               = it->second.eland_threshold;
+    2526       12818 :   _failsafe_threshold_            = it->second.failsafe_threshold;
+    2527       12818 :   _odometry_innovation_threshold_ = it->second.odometry_innovation_threshold;
+    2528             : 
+    2529             :   // | --------- calculate control errors and tilt angle -------- |
+    2530             : 
+    2531             :   // This means that the timerFailsafe only does its work when Controllers and Trackers produce valid output.
+    2532             :   // Cases when the commands are not valid should be handle in updateControllers() and updateTrackers() methods.
+    2533       12818 :   if (!last_tracker_cmd || !last_control_output.control_output) {
+    2534           8 :     return;
+    2535             :   }
+    2536             : 
+    2537             :   {
+    2538       12810 :     std::scoped_lock lock(mutex_attitude_error_);
+    2539             : 
+    2540       12810 :     tilt_error_ = 0;
+    2541       12810 :     yaw_error_  = 0;
+    2542             :   }
+    2543             : 
+    2544             :   {
+    2545             :     // TODO this whole scope is very clumsy
+    2546             : 
+    2547       12810 :     position_error_ = {};
+    2548             : 
+    2549       12810 :     if (last_tracker_cmd->use_position_horizontal && !std::holds_alternative<mrs_msgs::HwApiPositionCmd>(last_control_output.control_output.value())) {
+    2550             : 
+    2551       12810 :       std::scoped_lock lock(mutex_position_error_);
+    2552             : 
+    2553       12810 :       if (!position_error_) {
+    2554       12810 :         position_error_ = Eigen::Vector3d::Zero(3);
+    2555             :       }
+    2556             : 
+    2557       12810 :       position_error_.value()[0] = last_tracker_cmd->position.x - uav_state.pose.position.x;
+    2558       12810 :       position_error_.value()[1] = last_tracker_cmd->position.y - uav_state.pose.position.y;
+    2559             :     }
+    2560             : 
+    2561       12810 :     if (last_tracker_cmd->use_position_vertical && !std::holds_alternative<mrs_msgs::HwApiPositionCmd>(last_control_output.control_output.value())) {
+    2562             : 
+    2563       12810 :       std::scoped_lock lock(mutex_position_error_);
+    2564             : 
+    2565       12810 :       if (!position_error_) {
+    2566           0 :         position_error_ = Eigen::Vector3d::Zero(3);
+    2567             :       }
+    2568             : 
+    2569       12810 :       position_error_.value()[2] = last_tracker_cmd->position.z - uav_state.pose.position.z;
+    2570             :     }
+    2571             :   }
+    2572             : 
+    2573             :   // rotate the drone's z axis
+    2574       12810 :   tf2::Transform uav_state_transform = mrs_lib::AttitudeConverter(uav_state.pose.orientation);
+    2575       12810 :   tf2::Vector3   uav_z_in_world      = uav_state_transform * tf2::Vector3(0, 0, 1);
+    2576             : 
+    2577             :   // calculate the angle between the drone's z axis and the world's z axis
+    2578       12810 :   double tilt_angle = acos(uav_z_in_world.dot(tf2::Vector3(0, 0, 1)));
+    2579             : 
+    2580             :   // | ------------ calculate the tilt and yaw error ------------ |
+    2581             : 
+    2582             :   // | --------------------- the tilt error --------------------- |
+    2583             : 
+    2584       12810 :   if (last_control_output.desired_orientation) {
+    2585             : 
+    2586             :     // calculate the desired drone's z axis in the world frame
+    2587       11334 :     tf2::Transform attitude_cmd_transform = mrs_lib::AttitudeConverter(last_control_output.desired_orientation.value());
+    2588       11334 :     tf2::Vector3   uav_z_in_world_desired = attitude_cmd_transform * tf2::Vector3(0, 0, 1);
+    2589             : 
+    2590             :     {
+    2591       11334 :       std::scoped_lock lock(mutex_attitude_error_);
+    2592             : 
+    2593             :       // calculate the angle between the drone's z axis and the world's z axis
+    2594       11334 :       tilt_error_ = acos(uav_z_in_world.dot(uav_z_in_world_desired));
+    2595             : 
+    2596             :       // calculate the yaw error
+    2597       11334 :       double cmd_yaw = mrs_lib::AttitudeConverter(last_control_output.desired_orientation.value()).getYaw();
+    2598       11334 :       yaw_error_     = fabs(radians::diff(cmd_yaw, uav_yaw));
+    2599             :     }
+    2600             :   }
+    2601             : 
+    2602       12810 :   auto position_error          = mrs_lib::get_mutexed(mutex_position_error_, position_error_);
+    2603       12810 :   auto [tilt_error, yaw_error] = mrs_lib::get_mutexed(mutex_attitude_error_, tilt_error_, yaw_error_);
+    2604             : 
+    2605             :   // --------------------------------------------------------------
+    2606             :   // |   activate the failsafe controller in case of large error  |
+    2607             :   // --------------------------------------------------------------
+    2608             : 
+    2609       12810 :   if (position_error) {
+    2610             : 
+    2611       12810 :     if (position_error->norm() > _failsafe_threshold_ && !failsafe_triggered_) {
+    2612             : 
+    2613           1 :       auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2614             : 
+    2615           1 :       if ((ros::Time::now() - controller_tracker_switch_time).toSec() > 1.0) {
+    2616             : 
+    2617           1 :         if (!failsafe_triggered_) {
+    2618             : 
+    2619           1 :           ROS_ERROR("[ControlManager]: activating failsafe land: control_error=%.2f/%.2f m (x: %.2f, y: %.2f, z: %.2f)", position_error->norm(),
+    2620             :                     _failsafe_threshold_, position_error.value()[0], position_error.value()[1], position_error.value()[2]);
+    2621             : 
+    2622           1 :           failsafe();
+    2623             :         }
+    2624             :       }
+    2625             :     }
+    2626             :   }
+    2627             : 
+    2628             :   // --------------------------------------------------------------
+    2629             :   // |     activate emergency land in case of large innovation    |
+    2630             :   // --------------------------------------------------------------
+    2631             : 
+    2632       12810 :   if (_odometry_innovation_check_enabled_) {
+    2633             :     {
+    2634       12810 :       auto [x, y, z] = mrs_lib::getPosition(sh_odometry_innovation_.getMsg());
+    2635             : 
+    2636       12810 :       double heading = 0;
+    2637             :       try {
+    2638       12810 :         heading = mrs_lib::getHeading(sh_odometry_innovation_.getMsg());
+    2639             :       }
+    2640           0 :       catch (mrs_lib::AttitudeConverter::GetHeadingException& e) {
+    2641           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception caught: '%s'", e.what());
+    2642             :       }
+    2643             : 
+    2644       12810 :       double last_innovation = mrs_lib::geometry::dist(vec3_t(x, y, z), vec3_t(0, 0, 0));
+    2645             : 
+    2646       12810 :       if (last_innovation > _odometry_innovation_threshold_ || radians::diff(heading, 0) > M_PI_2) {
+    2647             : 
+    2648          43 :         auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2649             : 
+    2650          43 :         if ((ros::Time::now() - controller_tracker_switch_time).toSec() > 1.0) {
+    2651             : 
+    2652          33 :           if (!failsafe_triggered_ && !eland_triggered_) {
+    2653             : 
+    2654           1 :             ROS_ERROR("[ControlManager]: activating emergency land: odometry innovation too large: %.2f/%.2f (x: %.2f, y: %.2f, z: %.2f, heading: %.2f)",
+    2655             :                       last_innovation, _odometry_innovation_threshold_, x, y, z, heading);
+    2656             : 
+    2657           1 :             eland();
+    2658             :           }
+    2659             :         }
+    2660             :       }
+    2661             :     }
+    2662             :   }
+    2663             : 
+    2664             :   // --------------------------------------------------------------
+    2665             :   // |   activate emergency land in case of medium control error  |
+    2666             :   // --------------------------------------------------------------
+    2667             : 
+    2668             :   // | ------------------- tilt control error ------------------- |
+    2669             : 
+    2670       12810 :   if (_tilt_limit_eland_enabled_ && tilt_angle > _tilt_limit_eland_) {
+    2671             : 
+    2672           0 :     auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2673             : 
+    2674           0 :     if ((ros::Time::now() - controller_tracker_switch_time).toSec() > 1.0) {
+    2675             : 
+    2676           0 :       if (!failsafe_triggered_ && !eland_triggered_) {
+    2677             : 
+    2678           0 :         ROS_ERROR("[ControlManager]: activating emergency land: tilt angle too large (%.2f/%.2f deg)", (180.0 / M_PI) * tilt_angle,
+    2679             :                   (180.0 / M_PI) * _tilt_limit_eland_);
+    2680             : 
+    2681           0 :         eland();
+    2682             :       }
+    2683             :     }
+    2684             :   }
+    2685             : 
+    2686             :   // | ----------------- position control error ----------------- |
+    2687             : 
+    2688       12810 :   if (position_error) {
+    2689             : 
+    2690       12810 :     double error_size = position_error->norm();
+    2691             : 
+    2692       12810 :     if (error_size > _eland_threshold_ / 2.0) {
+    2693             : 
+    2694         159 :       auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2695             : 
+    2696         159 :       if ((ros::Time::now() - controller_tracker_switch_time).toSec() > 1.0) {
+    2697             : 
+    2698         150 :         if (!failsafe_triggered_ && !eland_triggered_) {
+    2699             : 
+    2700         111 :           ROS_DEBUG_THROTTLE(1.0, "[ControlManager]: releasing payload due to large position error");
+    2701             : 
+    2702         111 :           ungripSrv();
+    2703             :         }
+    2704             :       }
+    2705             :     }
+    2706             : 
+    2707       12810 :     if (error_size > _eland_threshold_) {
+    2708             : 
+    2709          40 :       auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2710             : 
+    2711          40 :       if ((ros::Time::now() - controller_tracker_switch_time).toSec() > 1.0) {
+    2712             : 
+    2713          37 :         if (!failsafe_triggered_ && !eland_triggered_) {
+    2714             : 
+    2715           1 :           ROS_ERROR("[ControlManager]: activating emergency land: position error %.2f/%.2f m (error x: %.2f, y: %.2f, z: %.2f)", error_size, _eland_threshold_,
+    2716             :                     position_error.value()[0], position_error.value()[1], position_error.value()[2]);
+    2717             : 
+    2718           1 :           eland();
+    2719             :         }
+    2720             :       }
+    2721             :     }
+    2722             :   }
+    2723             : 
+    2724             :   // | -------------------- yaw control error ------------------- |
+    2725             :   // do not have to mutex the yaw_error_ here since I am filling it in this function
+    2726             : 
+    2727       12810 :   if (_yaw_error_eland_enabled_ && yaw_error) {
+    2728             : 
+    2729       12810 :     if (yaw_error.value() > (_yaw_error_eland_ / 2.0)) {
+    2730             : 
+    2731           0 :       auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2732             : 
+    2733           0 :       if ((ros::Time::now() - controller_tracker_switch_time).toSec() > 1.0) {
+    2734             : 
+    2735           0 :         if (!failsafe_triggered_ && !eland_triggered_) {
+    2736             : 
+    2737           0 :           ROS_DEBUG_THROTTLE(1.0, "[ControlManager]: releasing payload: yaw error %.2f/%.2f deg", (180.0 / M_PI) * yaw_error.value(),
+    2738             :                              (180.0 / M_PI) * _yaw_error_eland_ / 2.0);
+    2739             : 
+    2740           0 :           ungripSrv();
+    2741             :         }
+    2742             :       }
+    2743             :     }
+    2744             : 
+    2745       12810 :     if (yaw_error.value() > _yaw_error_eland_) {
+    2746             : 
+    2747           0 :       auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2748             : 
+    2749           0 :       if ((ros::Time::now() - controller_tracker_switch_time).toSec() > 1.0) {
+    2750             : 
+    2751           0 :         if (!failsafe_triggered_ && !eland_triggered_) {
+    2752             : 
+    2753           0 :           ROS_ERROR("[ControlManager]: activating emergency land: yaw error %.2f/%.2f deg", (180.0 / M_PI) * yaw_error.value(),
+    2754             :                     (180.0 / M_PI) * _yaw_error_eland_);
+    2755             : 
+    2756           0 :           eland();
+    2757             :         }
+    2758             :       }
+    2759             :     }
+    2760             :   }
+    2761             : 
+    2762             :   // --------------------------------------------------------------
+    2763             :   // |      disarm the drone when the tilt exceeds the limit      |
+    2764             :   // --------------------------------------------------------------
+    2765       12810 :   if (_tilt_limit_disarm_enabled_ && tilt_angle > _tilt_limit_disarm_) {
+    2766             : 
+    2767           0 :     ROS_ERROR("[ControlManager]: tilt angle too large, disarming: tilt angle=%.2f/%.2f deg", (180.0 / M_PI) * tilt_angle, (180.0 / M_PI) * _tilt_limit_disarm_);
+    2768             : 
+    2769           0 :     arming(false);
+    2770             :   }
+    2771             : 
+    2772             :   // --------------------------------------------------------------
+    2773             :   // |     disarm the drone when tilt error exceeds the limit     |
+    2774             :   // --------------------------------------------------------------
+    2775             : 
+    2776       12810 :   if (_tilt_error_disarm_enabled_ && tilt_error) {
+    2777             : 
+    2778       12810 :     auto controller_tracker_switch_time = mrs_lib::get_mutexed(mutex_controller_tracker_switch_time_, controller_tracker_switch_time_);
+    2779             : 
+    2780             :     // the time from the last controller/tracker switch
+    2781             :     // fyi: we should not
+    2782       12810 :     double time_from_ctrl_tracker_switch = (ros::Time::now() - controller_tracker_switch_time).toSec();
+    2783             : 
+    2784             :     // if the tile error is over the threshold
+    2785             :     // && we are not ramping up during takeoff
+    2786       12810 :     if (fabs(tilt_error.value()) > _tilt_error_disarm_threshold_ && !last_control_output.diagnostics.ramping_up) {
+    2787             : 
+    2788             :       // only account for the error if some time passed from the last tracker/controller switch
+    2789           0 :       if (time_from_ctrl_tracker_switch > 1.0) {
+    2790             : 
+    2791             :         // if the threshold was not exceeded before
+    2792           0 :         if (!tilt_error_disarm_over_thr_) {
+    2793             : 
+    2794           0 :           tilt_error_disarm_over_thr_ = true;
+    2795           0 :           tilt_error_disarm_time_     = ros::Time::now();
+    2796             : 
+    2797           0 :           ROS_WARN("[ControlManager]: tilt error exceeded threshold (%.2f/%.2f deg)", (180.0 / M_PI) * tilt_error.value(),
+    2798             :                    (180.0 / M_PI) * _tilt_error_disarm_threshold_);
+    2799             : 
+    2800             :           // if it was exceeded before, just keep it
+    2801             :         } else {
+    2802             : 
+    2803           0 :           ROS_WARN_THROTTLE(0.1, "[ControlManager]: tilt error (%.2f deg) over threshold for %.2f s", (180.0 / M_PI) * tilt_error.value(),
+    2804             :                             (ros::Time::now() - tilt_error_disarm_time_).toSec());
+    2805             :         }
+    2806             : 
+    2807             :         // if the tile error is bad, but the controller just switched,
+    2808             :         // don't think its bad anymore
+    2809             :       } else {
+    2810             : 
+    2811           0 :         tilt_error_disarm_over_thr_ = false;
+    2812           0 :         tilt_error_disarm_time_     = ros::Time::now();
+    2813             :       }
+    2814             : 
+    2815             :       // if the tilt error is fine
+    2816             :     } else {
+    2817             : 
+    2818             :       // make it fine
+    2819       12810 :       tilt_error_disarm_over_thr_ = false;
+    2820       12810 :       tilt_error_disarm_time_     = ros::Time::now();
+    2821             :     }
+    2822             : 
+    2823             :     // calculate the time over the threshold
+    2824       12810 :     double tot = (ros::Time::now() - tilt_error_disarm_time_).toSec();
+    2825             : 
+    2826             :     // if the tot exceeds the limit (and if we are actually over the threshold)
+    2827       12810 :     if (tilt_error_disarm_over_thr_ && (tot > _tilt_error_disarm_timeout_)) {
+    2828             : 
+    2829           0 :       bool is_flying = offboard_mode_ && active_tracker_idx != _null_tracker_idx_;
+    2830             : 
+    2831             :       // only when flying and not in failsafe
+    2832           0 :       if (is_flying) {
+    2833             : 
+    2834           0 :         ROS_ERROR("[ControlManager]: tilt error too large for %.2f s, disarming", tot);
+    2835             : 
+    2836           0 :         toggleOutput(false);
+    2837           0 :         arming(false);
+    2838             :       }
+    2839             :     }
+    2840             :   }
+    2841             : 
+    2842             :   // | --------- dropping out of OFFBOARD in mid flight --------- |
+    2843             : 
+    2844             :   // if we are not in offboard and the drone is in mid air (NullTracker is not active)
+    2845       12810 :   if (offboard_mode_was_true_ && !offboard_mode_ && active_tracker_idx != _null_tracker_idx_) {
+    2846             : 
+    2847           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: we fell out of OFFBOARD in mid air, disabling output");
+    2848             : 
+    2849           0 :     toggleOutput(false);
+    2850             :   }
+    2851             : }  // namespace control_manager
+    2852             : 
+    2853             : //}
+    2854             : 
+    2855             : /* //{ timerEland() */
+    2856             : 
+    2857         235 : void ControlManager::timerEland(const ros::TimerEvent& event) {
+    2858             : 
+    2859         235 :   if (!is_initialized_)
+    2860           0 :     return;
+    2861             : 
+    2862         470 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerEland", _elanding_timer_rate_, 0.01, event);
+    2863         470 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerEland", scope_timer_logger_, scope_timer_enabled_);
+    2864             : 
+    2865             :   // copy member variables
+    2866         235 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    2867             : 
+    2868         235 :   if (!last_control_output.control_output) {
+    2869           0 :     return;
+    2870             :   }
+    2871             : 
+    2872         235 :   double throttle = 0;
+    2873             : 
+    2874         235 :   if (std::holds_alternative<mrs_msgs::HwApiAttitudeCmd>(last_control_output.control_output.value())) {
+    2875           0 :     throttle = std::get<mrs_msgs::HwApiAttitudeCmd>(last_control_output.control_output.value()).throttle;
+    2876         235 :   } else if (std::holds_alternative<mrs_msgs::HwApiAttitudeRateCmd>(last_control_output.control_output.value())) {
+    2877         235 :     throttle = std::get<mrs_msgs::HwApiAttitudeRateCmd>(last_control_output.control_output.value()).throttle;
+    2878           0 :   } else if (std::holds_alternative<mrs_msgs::HwApiControlGroupCmd>(last_control_output.control_output.value())) {
+    2879           0 :     throttle = std::get<mrs_msgs::HwApiControlGroupCmd>(last_control_output.control_output.value()).throttle;
+    2880             :   } else {
+    2881           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: TODO: implement eland timer for this control mode");
+    2882           0 :     return;
+    2883             :   }
+    2884             : 
+    2885         235 :   if (current_state_landing_ == IDLE_STATE) {
+    2886             : 
+    2887           0 :     return;
+    2888             : 
+    2889         235 :   } else if (current_state_landing_ == LANDING_STATE) {
+    2890             : 
+    2891         235 :     if (!last_control_output.control_output) {
+    2892           0 :       ROS_WARN_THROTTLE(1.0, "[ControlManager]: timerEland: last_control_output has not been initialized, returning");
+    2893           0 :       ROS_WARN_THROTTLE(1.0, "[ControlManager]: tip: the RC eland is probably triggered");
+    2894           0 :       return;
+    2895             :     }
+    2896             : 
+    2897             :     // recalculate the mass based on the throttle
+    2898         235 :     throttle_mass_estimate_ = mrs_lib::quadratic_throttle_model::throttleToForce(common_handlers_->throttle_model, throttle) / common_handlers_->g;
+    2899         235 :     ROS_INFO_THROTTLE(1.0, "[ControlManager]: landing: initial mass: %.2f throttle_mass_estimate: %.2f", landing_uav_mass_, throttle_mass_estimate_);
+    2900             : 
+    2901             :     // condition for automatic motor turn off
+    2902         235 :     if (((throttle_mass_estimate_ < _elanding_cutoff_mass_factor_ * landing_uav_mass_) || throttle < 0.01)) {
+    2903          66 :       if (!throttle_under_threshold_) {
+    2904             : 
+    2905           3 :         throttle_mass_estimate_first_time_ = ros::Time::now();
+    2906           3 :         throttle_under_threshold_          = true;
+    2907             :       }
+    2908             : 
+    2909          66 :       ROS_INFO_THROTTLE(0.1, "[ControlManager]: throttle is under cutoff factor for %.2f s", (ros::Time::now() - throttle_mass_estimate_first_time_).toSec());
+    2910             : 
+    2911             :     } else {
+    2912         169 :       throttle_mass_estimate_first_time_ = ros::Time::now();
+    2913         169 :       throttle_under_threshold_          = false;
+    2914             :     }
+    2915             : 
+    2916         235 :     if (throttle_under_threshold_ && ((ros::Time::now() - throttle_mass_estimate_first_time_).toSec() > _elanding_cutoff_timeout_)) {
+    2917             :       // enable callbacks? ... NO
+    2918             : 
+    2919           3 :       ROS_INFO("[ControlManager]: reached cutoff throttle, disabling output");
+    2920           3 :       toggleOutput(false);
+    2921             : 
+    2922             :       // disarm the drone
+    2923           3 :       if (_eland_disarm_enabled_) {
+    2924             : 
+    2925           3 :         ROS_INFO("[ControlManager]: calling for disarm");
+    2926           3 :         arming(false);
+    2927             :       }
+    2928             : 
+    2929           3 :       shutdown();
+    2930             : 
+    2931           3 :       changeLandingState(IDLE_STATE);
+    2932             : 
+    2933           3 :       ROS_WARN("[ControlManager]: emergency landing finished");
+    2934             : 
+    2935           3 :       ROS_DEBUG("[ControlManager]: stopping eland timer");
+    2936           3 :       timer_eland_.stop();
+    2937           3 :       ROS_DEBUG("[ControlManager]: eland timer stopped");
+    2938             : 
+    2939             :       // we should NOT set eland_triggered_=true
+    2940             :     }
+    2941             :   }
+    2942             : }
+    2943             : 
+    2944             : //}
+    2945             : 
+    2946             : /* //{ timerFailsafe() */
+    2947             : 
+    2948        1398 : void ControlManager::timerFailsafe(const ros::TimerEvent& event) {
+    2949             : 
+    2950        1398 :   if (!is_initialized_) {
+    2951           0 :     return;
+    2952             :   }
+    2953             : 
+    2954        1398 :   ROS_INFO_ONCE("[ControlManager]: timerFailsafe() spinning");
+    2955             : 
+    2956        2796 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerFailsafe", _failsafe_timer_rate_, 0.01, event);
+    2957        2796 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerFailsafe", scope_timer_logger_, scope_timer_enabled_);
+    2958             : 
+    2959             :   // copy member variables
+    2960        1398 :   auto uav_state = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    2961             : 
+    2962        1398 :   updateControllers(uav_state);
+    2963             : 
+    2964        1398 :   publish();
+    2965             : 
+    2966        1398 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    2967             : 
+    2968        1398 :   if (!last_control_output.control_output) {
+    2969           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: timerFailsafe: the control output produced by the failsafe controller is empty!");
+    2970           0 :     return;
+    2971             :   }
+    2972             : 
+    2973        1398 :   auto throttle = extractThrottle(last_control_output);
+    2974             : 
+    2975        1398 :   if (!throttle) {
+    2976           0 :     ROS_DEBUG_THROTTLE(1.0, "[ControlManager]: FailsafeTimer: could not extract throttle out of the last control output");
+    2977           0 :     return;
+    2978             :   }
+    2979             : 
+    2980        1398 :   double throttle_mass_estimate_ = mrs_lib::quadratic_throttle_model::throttleToForce(common_handlers_->throttle_model, throttle.value()) / common_handlers_->g;
+    2981        1398 :   ROS_INFO_THROTTLE(1.0, "[ControlManager]: failsafe: initial mass: %.2f throttle_mass_estimate: %.2f", landing_uav_mass_, throttle_mass_estimate_);
+    2982             : 
+    2983             :   // condition for automatic motor turn off
+    2984        1398 :   if (((throttle_mass_estimate_ < _elanding_cutoff_mass_factor_ * landing_uav_mass_))) {
+    2985             : 
+    2986         202 :     if (!throttle_under_threshold_) {
+    2987             : 
+    2988           1 :       throttle_mass_estimate_first_time_ = ros::Time::now();
+    2989           1 :       throttle_under_threshold_          = true;
+    2990             :     }
+    2991             : 
+    2992         202 :     ROS_INFO_THROTTLE(0.1, "[ControlManager]: throttle is under cutoff factor for %.2f s", (ros::Time::now() - throttle_mass_estimate_first_time_).toSec());
+    2993             : 
+    2994             :   } else {
+    2995             : 
+    2996        1196 :     throttle_mass_estimate_first_time_ = ros::Time::now();
+    2997        1196 :     throttle_under_threshold_          = false;
+    2998             :   }
+    2999             : 
+    3000             :   // condition for automatic motor turn off
+    3001        1398 :   if (throttle_under_threshold_ && ((ros::Time::now() - throttle_mass_estimate_first_time_).toSec() > _elanding_cutoff_timeout_)) {
+    3002             : 
+    3003           1 :     ROS_INFO_THROTTLE(1.0, "[ControlManager]: detecting zero throttle, disarming");
+    3004             : 
+    3005           1 :     arming(false);
+    3006             :   }
+    3007             : }
+    3008             : 
+    3009             : //}
+    3010             : 
+    3011             : /* //{ timerJoystick() */
+    3012             : 
+    3013        3247 : void ControlManager::timerJoystick(const ros::TimerEvent& event) {
+    3014             : 
+    3015        3247 :   if (!is_initialized_) {
+    3016           0 :     return;
+    3017             :   }
+    3018             : 
+    3019        9741 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerJoystick", _status_timer_rate_, 0.05, event);
+    3020        9741 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerJoystick", scope_timer_logger_, scope_timer_enabled_);
+    3021             : 
+    3022        6494 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    3023             : 
+    3024             :   // if start was pressed and held for > 3.0 s
+    3025        3247 :   if (joystick_start_pressed_ && joystick_start_press_time_ != ros::Time(0) && (ros::Time::now() - joystick_start_press_time_).toSec() > 3.0) {
+    3026             : 
+    3027           0 :     joystick_start_press_time_ = ros::Time(0);
+    3028             : 
+    3029           0 :     ROS_INFO("[ControlManager]: transitioning to joystick control: activating '%s' and '%s'", _joystick_tracker_name_.c_str(),
+    3030             :              _joystick_controller_name_.c_str());
+    3031             : 
+    3032           0 :     joystick_start_pressed_ = false;
+    3033             : 
+    3034           0 :     switchTracker(_joystick_tracker_name_);
+    3035           0 :     switchController(_joystick_controller_name_);
+    3036             :   }
+    3037             : 
+    3038             :   // if RT+LT were pressed and held for > 0.1 s
+    3039        3247 :   if (joystick_failsafe_pressed_ && joystick_failsafe_press_time_ != ros::Time(0) && (ros::Time::now() - joystick_failsafe_press_time_).toSec() > 0.1) {
+    3040             : 
+    3041           0 :     joystick_failsafe_press_time_ = ros::Time(0);
+    3042             : 
+    3043           0 :     ROS_INFO("[ControlManager]: activating failsafe by joystick");
+    3044             : 
+    3045           0 :     joystick_failsafe_pressed_ = false;
+    3046             : 
+    3047           0 :     failsafe();
+    3048             :   }
+    3049             : 
+    3050             :   // if joypads were pressed and held for > 0.1 s
+    3051        3247 :   if (joystick_eland_pressed_ && joystick_eland_press_time_ != ros::Time(0) && (ros::Time::now() - joystick_eland_press_time_).toSec() > 0.1) {
+    3052             : 
+    3053           0 :     joystick_eland_press_time_ = ros::Time(0);
+    3054             : 
+    3055           0 :     ROS_INFO("[ControlManager]: activating eland by joystick");
+    3056             : 
+    3057           0 :     joystick_failsafe_pressed_ = false;
+    3058             : 
+    3059           0 :     eland();
+    3060             :   }
+    3061             : 
+    3062             :   // if back was pressed and held for > 0.1 s
+    3063        3247 :   if (joystick_back_pressed_ && joystick_back_press_time_ != ros::Time(0) && (ros::Time::now() - joystick_back_press_time_).toSec() > 0.1) {
+    3064             : 
+    3065           0 :     joystick_back_press_time_ = ros::Time(0);
+    3066             : 
+    3067             :     // activate/deactivate the joystick goto functionality
+    3068           0 :     joystick_goto_enabled_ = !joystick_goto_enabled_;
+    3069             : 
+    3070           0 :     ROS_INFO("[ControlManager]: joystick control %s", joystick_goto_enabled_ ? "activated" : "deactivated");
+    3071             :   }
+    3072             : 
+    3073             :   // if the GOTO functionality is enabled...
+    3074        3247 :   if (joystick_goto_enabled_ && sh_joystick_.hasMsg()) {
+    3075             : 
+    3076           0 :     auto joystick_data = sh_joystick_.getMsg();
+    3077             : 
+    3078             :     // create the reference
+    3079             : 
+    3080           0 :     mrs_msgs::Vec4::Request request;
+    3081             : 
+    3082           0 :     if (fabs(joystick_data->axes[_channel_pitch_]) >= 0.05 || fabs(joystick_data->axes[_channel_roll_]) >= 0.05 ||
+    3083           0 :         fabs(joystick_data->axes[_channel_heading_]) >= 0.05 || fabs(joystick_data->axes[_channel_throttle_]) >= 0.05) {
+    3084             : 
+    3085           0 :       if (_joystick_mode_ == 0) {
+    3086             : 
+    3087           0 :         request.goal[REF_X]       = _channel_mult_pitch_ * joystick_data->axes[_channel_pitch_] * _joystick_carrot_distance_;
+    3088           0 :         request.goal[REF_Y]       = _channel_mult_roll_ * joystick_data->axes[_channel_roll_] * _joystick_carrot_distance_;
+    3089           0 :         request.goal[REF_Z]       = _channel_mult_throttle_ * joystick_data->axes[_channel_throttle_];
+    3090           0 :         request.goal[REF_HEADING] = _channel_mult_heading_ * joystick_data->axes[_channel_heading_];
+    3091             : 
+    3092           0 :         mrs_msgs::Vec4::Response response;
+    3093             : 
+    3094           0 :         callbackGotoFcu(request, response);
+    3095             : 
+    3096           0 :       } else if (_joystick_mode_ == 1) {
+    3097             : 
+    3098           0 :         mrs_msgs::TrajectoryReference trajectory;
+    3099             : 
+    3100           0 :         double dt = 0.2;
+    3101             : 
+    3102           0 :         trajectory.fly_now         = true;
+    3103           0 :         trajectory.header.frame_id = "fcu_untilted";
+    3104           0 :         trajectory.use_heading     = true;
+    3105           0 :         trajectory.dt              = dt;
+    3106             : 
+    3107           0 :         mrs_msgs::Reference point;
+    3108           0 :         point.position.x = 0;
+    3109           0 :         point.position.y = 0;
+    3110           0 :         point.position.z = 0;
+    3111           0 :         point.heading    = 0;
+    3112             : 
+    3113           0 :         trajectory.points.push_back(point);
+    3114             : 
+    3115           0 :         double speed = 1.0;
+    3116             : 
+    3117           0 :         for (int i = 0; i < 50; i++) {
+    3118             : 
+    3119           0 :           point.position.x += _channel_mult_pitch_ * joystick_data->axes[_channel_pitch_] * (speed * dt);
+    3120           0 :           point.position.y += _channel_mult_roll_ * joystick_data->axes[_channel_roll_] * (speed * dt);
+    3121           0 :           point.position.z += _channel_mult_throttle_ * joystick_data->axes[_channel_throttle_] * (speed * dt);
+    3122           0 :           point.heading = _channel_mult_heading_ * joystick_data->axes[_channel_heading_];
+    3123             : 
+    3124           0 :           trajectory.points.push_back(point);
+    3125             :         }
+    3126             : 
+    3127           0 :         setTrajectoryReference(trajectory);
+    3128             :       }
+    3129             :     }
+    3130             :   }
+    3131             : 
+    3132        3247 :   if (rc_goto_active_ && last_tracker_cmd && sh_hw_api_rc_.hasMsg()) {
+    3133             : 
+    3134             :     // create the reference
+    3135           0 :     mrs_msgs::VelocityReferenceStampedSrv::Request request;
+    3136             : 
+    3137           0 :     double des_x       = 0;
+    3138           0 :     double des_y       = 0;
+    3139           0 :     double des_z       = 0;
+    3140           0 :     double des_heading = 0;
+    3141             : 
+    3142           0 :     bool nothing_to_do = true;
+    3143             : 
+    3144             :     // copy member variables
+    3145           0 :     mrs_msgs::HwApiRcChannelsConstPtr rc_channels = sh_hw_api_rc_.getMsg();
+    3146             : 
+    3147           0 :     if (rc_channels->channels.size() < 4) {
+    3148             : 
+    3149           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: RC control channel numbers are out of range (the # of channels in rc/in topic is %d)",
+    3150             :                          int(rc_channels->channels.size()));
+    3151           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: tip: this could be caused by the RC failsafe not being configured!");
+    3152             : 
+    3153             :     } else {
+    3154             : 
+    3155           0 :       double tmp_x       = RCChannelToRange(rc_channels->channels[_rc_channel_pitch_], _rc_horizontal_speed_, 0.1);
+    3156           0 :       double tmp_y       = -RCChannelToRange(rc_channels->channels[_rc_channel_roll_], _rc_horizontal_speed_, 0.1);
+    3157           0 :       double tmp_z       = RCChannelToRange(rc_channels->channels[_rc_channel_throttle_], _rc_vertical_speed_, 0.3);
+    3158           0 :       double tmp_heading = -RCChannelToRange(rc_channels->channels[_rc_channel_heading_], _rc_heading_rate_, 0.1);
+    3159             : 
+    3160           0 :       if (abs(tmp_x) > 1e-3) {
+    3161           0 :         des_x         = tmp_x;
+    3162           0 :         nothing_to_do = false;
+    3163             :       }
+    3164             : 
+    3165           0 :       if (abs(tmp_y) > 1e-3) {
+    3166           0 :         des_y         = tmp_y;
+    3167           0 :         nothing_to_do = false;
+    3168             :       }
+    3169             : 
+    3170           0 :       if (abs(tmp_z) > 1e-3) {
+    3171           0 :         des_z         = tmp_z;
+    3172           0 :         nothing_to_do = false;
+    3173             :       }
+    3174             : 
+    3175           0 :       if (abs(tmp_heading) > 1e-3) {
+    3176           0 :         des_heading   = tmp_heading;
+    3177           0 :         nothing_to_do = false;
+    3178             :       }
+    3179             :     }
+    3180             : 
+    3181           0 :     if (!nothing_to_do) {
+    3182             : 
+    3183           0 :       request.reference.header.frame_id = "fcu_untilted";
+    3184             : 
+    3185           0 :       request.reference.reference.use_heading_rate = true;
+    3186             : 
+    3187           0 :       request.reference.reference.velocity.x   = des_x;
+    3188           0 :       request.reference.reference.velocity.y   = des_y;
+    3189           0 :       request.reference.reference.velocity.z   = des_z;
+    3190           0 :       request.reference.reference.heading_rate = des_heading;
+    3191             : 
+    3192           0 :       mrs_msgs::VelocityReferenceStampedSrv::Response response;
+    3193             : 
+    3194             :       // disable callbacks of all trackers
+    3195           0 :       std_srvs::SetBoolRequest req_enable_callbacks;
+    3196             : 
+    3197             :       // enable the callbacks for the active tracker
+    3198           0 :       req_enable_callbacks.data = true;
+    3199             :       {
+    3200           0 :         std::scoped_lock lock(mutex_tracker_list_);
+    3201             : 
+    3202           0 :         tracker_list_[active_tracker_idx_]->enableCallbacks(
+    3203           0 :             std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    3204             :       }
+    3205             : 
+    3206           0 :       callbacks_enabled_ = true;
+    3207             : 
+    3208           0 :       callbackVelocityReferenceService(request, response);
+    3209             : 
+    3210           0 :       callbacks_enabled_ = false;
+    3211             : 
+    3212           0 :       ROS_INFO_THROTTLE(1.0, "[ControlManager]: goto by RC with speed x=%.2f, y=%.2f, z=%.2f, heading_rate=%.2f", des_x, des_y, des_z, des_heading);
+    3213             : 
+    3214             :       // disable the callbacks back again
+    3215           0 :       req_enable_callbacks.data = false;
+    3216             :       {
+    3217           0 :         std::scoped_lock lock(mutex_tracker_list_);
+    3218             : 
+    3219           0 :         tracker_list_[active_tracker_idx_]->enableCallbacks(
+    3220           0 :             std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    3221             :       }
+    3222             :     }
+    3223             :   }
+    3224             : }
+    3225             : 
+    3226             : //}
+    3227             : 
+    3228             : /* //{ timerBumper() */
+    3229             : 
+    3230           0 : void ControlManager::timerBumper(const ros::TimerEvent& event) {
+    3231             : 
+    3232           0 :   if (!is_initialized_)
+    3233           0 :     return;
+    3234             : 
+    3235           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerBumper", _bumper_timer_rate_, 0.05, event);
+    3236           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerBumper", scope_timer_logger_, scope_timer_enabled_);
+    3237             : 
+    3238           0 :   if (!bumper_enabled_) {
+    3239           0 :     return;
+    3240             :   }
+    3241             : 
+    3242           0 :   if (!isFlyingNormally()) {
+    3243           0 :     return;
+    3244             :   }
+    3245             : 
+    3246           0 :   if (!got_uav_state_) {
+    3247           0 :     return;
+    3248             :   }
+    3249             : 
+    3250           0 :   if ((ros::Time::now() - sh_bumper_.lastMsgTime()).toSec() > 1.0) {
+    3251           0 :     return;
+    3252             :   }
+    3253             : 
+    3254             :   // --------------------------------------------------------------
+    3255             :   // |                      bumper repulsion                      |
+    3256             :   // --------------------------------------------------------------
+    3257             : 
+    3258           0 :   bumperPushFromObstacle();
+    3259             : }
+    3260             : 
+    3261             : //}
+    3262             : 
+    3263             : /* //{ timerPirouette() */
+    3264             : 
+    3265           0 : void ControlManager::timerPirouette(const ros::TimerEvent& event) {
+    3266             : 
+    3267           0 :   if (!is_initialized_)
+    3268           0 :     return;
+    3269             : 
+    3270           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerPirouette", _pirouette_timer_rate_, 0.01, event);
+    3271           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerPirouette", scope_timer_logger_, scope_timer_enabled_);
+    3272             : 
+    3273           0 :   pirouette_iterator_++;
+    3274             : 
+    3275           0 :   double pirouette_duration  = (2 * M_PI) / _pirouette_speed_;
+    3276           0 :   double pirouette_n_steps   = pirouette_duration * _pirouette_timer_rate_;
+    3277           0 :   double pirouette_step_size = (2 * M_PI) / pirouette_n_steps;
+    3278             : 
+    3279           0 :   if (rc_escalating_failsafe_triggered_ || failsafe_triggered_ || eland_triggered_ || (pirouette_iterator_ > pirouette_duration * _pirouette_timer_rate_)) {
+    3280             : 
+    3281           0 :     _pirouette_enabled_ = false;
+    3282           0 :     timer_pirouette_.stop();
+    3283             : 
+    3284           0 :     setCallbacks(true);
+    3285             : 
+    3286           0 :     return;
+    3287             :   }
+    3288             : 
+    3289             :   // set the reference
+    3290           0 :   mrs_msgs::ReferenceStamped reference_request;
+    3291             : 
+    3292           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    3293             : 
+    3294           0 :   reference_request.header.frame_id      = "";
+    3295           0 :   reference_request.header.stamp         = ros::Time(0);
+    3296           0 :   reference_request.reference.position.x = last_tracker_cmd->position.x;
+    3297           0 :   reference_request.reference.position.y = last_tracker_cmd->position.y;
+    3298           0 :   reference_request.reference.position.z = last_tracker_cmd->position.z;
+    3299           0 :   reference_request.reference.heading    = pirouette_initial_heading_ + pirouette_iterator_ * pirouette_step_size;
+    3300             : 
+    3301             :   // enable the callbacks for the active tracker
+    3302             :   {
+    3303           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    3304             : 
+    3305           0 :     std_srvs::SetBoolRequest req_enable_callbacks;
+    3306           0 :     req_enable_callbacks.data = true;
+    3307             : 
+    3308           0 :     tracker_list_[active_tracker_idx_]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    3309             : 
+    3310           0 :     callbacks_enabled_ = true;
+    3311             :   }
+    3312             : 
+    3313           0 :   setReference(reference_request);
+    3314             : 
+    3315             :   {
+    3316           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    3317             : 
+    3318             :     // disable the callbacks for the active tracker
+    3319           0 :     std_srvs::SetBoolRequest req_enable_callbacks;
+    3320           0 :     req_enable_callbacks.data = false;
+    3321             : 
+    3322           0 :     tracker_list_[active_tracker_idx_]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    3323             : 
+    3324           0 :     callbacks_enabled_ = false;
+    3325             :   }
+    3326             : }
+    3327             : 
+    3328             : //}
+    3329             : 
+    3330             : // --------------------------------------------------------------
+    3331             : // |                           asyncs                           |
+    3332             : // --------------------------------------------------------------
+    3333             : 
+    3334             : /* asyncControl() //{ */
+    3335             : 
+    3336        8285 : void ControlManager::asyncControl(void) {
+    3337             : 
+    3338        8285 :   if (!is_initialized_)
+    3339           0 :     return;
+    3340             : 
+    3341       16570 :   mrs_lib::AtomicScopeFlag unset_running(running_async_control_);
+    3342             : 
+    3343       24855 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("asyncControl");
+    3344       24855 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::asyncControl", scope_timer_logger_, scope_timer_enabled_);
+    3345             : 
+    3346             :   // copy member variables
+    3347       16570 :   auto uav_state           = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    3348        8285 :   auto current_constraints = mrs_lib::get_mutexed(mutex_constraints_, current_constraints_);
+    3349             : 
+    3350        8285 :   if (!failsafe_triggered_) {  // when failsafe is triggered, updateControllers() and publish() is called in timerFailsafe()
+    3351             : 
+    3352             :     // run the safety timer
+    3353             :     // in the case of large control errors, the safety mechanisms will be triggered before the controllers and trackers are updated...
+    3354        6839 :     while (running_safety_timer_) {
+    3355             : 
+    3356          33 :       ROS_DEBUG("[ControlManager]: waiting for safety timer to finish");
+    3357          33 :       ros::Duration wait(0.001);
+    3358          33 :       wait.sleep();
+    3359             : 
+    3360          33 :       if (!running_safety_timer_) {
+    3361          33 :         ROS_DEBUG("[ControlManager]: safety timer finished");
+    3362          33 :         break;
+    3363             :       }
+    3364             :     }
+    3365             : 
+    3366        6839 :     ros::TimerEvent safety_timer_event;
+    3367        6839 :     timerSafety(safety_timer_event);
+    3368             : 
+    3369        6839 :     updateTrackers();
+    3370             : 
+    3371        6839 :     updateControllers(uav_state);
+    3372             : 
+    3373        6839 :     if (got_constraints_) {
+    3374             : 
+    3375             :       // update the constraints to trackers, if need to
+    3376        6803 :       auto enforce = enforceControllersConstraints(current_constraints);
+    3377             : 
+    3378        6803 :       if (enforce && !constraints_being_enforced_) {
+    3379             : 
+    3380           5 :         setConstraintsToTrackers(enforce.value());
+    3381           5 :         mrs_lib::set_mutexed(mutex_constraints_, enforce.value(), sanitized_constraints_);
+    3382             : 
+    3383           5 :         constraints_being_enforced_ = true;
+    3384             : 
+    3385           5 :         auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    3386             : 
+    3387           5 :         ROS_WARN_THROTTLE(1.0, "[ControlManager]: the controller '%s' is enforcing constraints over the ConstraintManager",
+    3388             :                           _controller_names_[active_controller_idx].c_str());
+    3389             : 
+    3390        6798 :       } else if (!enforce && constraints_being_enforced_) {
+    3391             : 
+    3392           5 :         ROS_INFO_THROTTLE(1.0, "[ControlManager]: constraint values returned to original values");
+    3393             : 
+    3394           5 :         constraints_being_enforced_ = false;
+    3395             : 
+    3396           5 :         mrs_lib::set_mutexed(mutex_constraints_, current_constraints, sanitized_constraints_);
+    3397             : 
+    3398           5 :         setConstraintsToTrackers(current_constraints);
+    3399             :       }
+    3400             :     }
+    3401             : 
+    3402        6839 :     publish();
+    3403             :   }
+    3404             : 
+    3405             :   // if odometry switch happened, we finish it here and turn the safety timer back on
+    3406        8285 :   if (odometry_switch_in_progress_) {
+    3407             : 
+    3408           0 :     ROS_DEBUG("[ControlManager]: starting safety timer");
+    3409           0 :     timer_safety_.start();
+    3410           0 :     ROS_DEBUG("[ControlManager]: safety timer started");
+    3411           0 :     odometry_switch_in_progress_ = false;
+    3412             : 
+    3413             :     {
+    3414           0 :       std::scoped_lock lock(mutex_uav_state_);
+    3415             : 
+    3416           0 :       ROS_INFO("[ControlManager]: odometry after switch: x=%.2f, y=%.2f, z=%.2f, heading=%.2f", uav_state.pose.position.x, uav_state.pose.position.y,
+    3417             :                uav_state.pose.position.z, uav_heading_);
+    3418             :     }
+    3419             :   }
+    3420             : }
+    3421             : 
+    3422             : //}
+    3423             : 
+    3424             : // --------------------------------------------------------------
+    3425             : // |                          callbacks                         |
+    3426             : // --------------------------------------------------------------
+    3427             : 
+    3428             : // | --------------------- topic callbacks -------------------- |
+    3429             : 
+    3430             : /* //{ callbackOdometry() */
+    3431             : 
+    3432           0 : void ControlManager::callbackOdometry(const nav_msgs::Odometry::ConstPtr msg) {
+    3433             : 
+    3434           0 :   if (!is_initialized_)
+    3435           0 :     return;
+    3436             : 
+    3437           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackOdometry");
+    3438           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackOdometry", scope_timer_logger_, scope_timer_enabled_);
+    3439             : 
+    3440           0 :   nav_msgs::OdometryConstPtr odom = msg;
+    3441             : 
+    3442             :   // | ------------------ check for time stamp ------------------ |
+    3443             : 
+    3444             :   {
+    3445           0 :     std::scoped_lock lock(mutex_uav_state_);
+    3446             : 
+    3447           0 :     if (uav_state_.header.stamp == odom->header.stamp) {
+    3448           0 :       return;
+    3449             :     }
+    3450             :   }
+    3451             : 
+    3452             :   // | --------------------- check for nans --------------------- |
+    3453             : 
+    3454           0 :   if (!validateOdometry(*odom, "ControlManager", "odometry")) {
+    3455           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: incoming 'odometry' contains invalid values, throwing it away");
+    3456           0 :     return;
+    3457             :   }
+    3458             : 
+    3459             :   // | ---------------------- frame switch ---------------------- |
+    3460             : 
+    3461             :   /* Odometry frame switch //{ */
+    3462             : 
+    3463             :   // | -- prepare an OdometryConstPtr for trackers & controllers -- |
+    3464             : 
+    3465           0 :   mrs_msgs::UavState uav_state_odom;
+    3466             : 
+    3467           0 :   uav_state_odom.header   = odom->header;
+    3468           0 :   uav_state_odom.pose     = odom->pose.pose;
+    3469           0 :   uav_state_odom.velocity = odom->twist.twist;
+    3470             : 
+    3471             :   // | ----- check for change in odometry frame of reference ---- |
+    3472             : 
+    3473           0 :   if (got_uav_state_) {
+    3474             : 
+    3475           0 :     if (odom->header.frame_id != uav_state_.header.frame_id) {
+    3476             : 
+    3477           0 :       ROS_INFO("[ControlManager]: detecting switch of odometry frame");
+    3478             :       {
+    3479           0 :         std::scoped_lock lock(mutex_uav_state_);
+    3480             : 
+    3481           0 :         ROS_INFO("[ControlManager]: odometry before switch: x=%.2f, y=%.2f, z=%.2f, heading=%.2f", uav_state_.pose.position.x, uav_state_.pose.position.y,
+    3482             :                  uav_state_.pose.position.z, uav_heading_);
+    3483             :       }
+    3484             : 
+    3485           0 :       odometry_switch_in_progress_ = true;
+    3486             : 
+    3487             :       // we have to stop safety timer, otherwise it will interfere
+    3488           0 :       ROS_DEBUG("[ControlManager]: stopping the safety timer");
+    3489           0 :       timer_safety_.stop();
+    3490           0 :       ROS_DEBUG("[ControlManager]: safety timer stopped");
+    3491             : 
+    3492             :       // wait for the safety timer to stop if its running
+    3493           0 :       while (running_safety_timer_) {
+    3494             : 
+    3495           0 :         ROS_DEBUG("[ControlManager]: waiting for safety timer to finish");
+    3496           0 :         ros::Duration wait(0.001);
+    3497           0 :         wait.sleep();
+    3498             : 
+    3499           0 :         if (!running_safety_timer_) {
+    3500           0 :           ROS_DEBUG("[ControlManager]: safety timer finished");
+    3501           0 :           break;
+    3502             :         }
+    3503             :       }
+    3504             : 
+    3505             :       // we have to also for the oneshot control timer to finish
+    3506           0 :       while (running_async_control_) {
+    3507             : 
+    3508           0 :         ROS_DEBUG("[ControlManager]: waiting for control timer to finish");
+    3509           0 :         ros::Duration wait(0.001);
+    3510           0 :         wait.sleep();
+    3511             : 
+    3512           0 :         if (!running_async_control_) {
+    3513           0 :           ROS_DEBUG("[ControlManager]: control timer finished");
+    3514           0 :           break;
+    3515             :         }
+    3516             :       }
+    3517             : 
+    3518             :       {
+    3519           0 :         std::scoped_lock lock(mutex_controller_list_, mutex_tracker_list_);
+    3520             : 
+    3521           0 :         tracker_list_[active_tracker_idx_]->switchOdometrySource(uav_state_odom);
+    3522           0 :         controller_list_[active_controller_idx_]->switchOdometrySource(uav_state_odom);
+    3523             :       }
+    3524             :     }
+    3525             :   }
+    3526             : 
+    3527             :   //}
+    3528             : 
+    3529             :   // | ----------- copy the odometry to the uav_state ----------- |
+    3530             : 
+    3531             :   {
+    3532           0 :     std::scoped_lock lock(mutex_uav_state_);
+    3533             : 
+    3534           0 :     previous_uav_state_ = uav_state_;
+    3535             : 
+    3536           0 :     uav_state_ = mrs_msgs::UavState();
+    3537             : 
+    3538           0 :     uav_state_.header           = odom->header;
+    3539           0 :     uav_state_.pose             = odom->pose.pose;
+    3540           0 :     uav_state_.velocity.angular = odom->twist.twist.angular;
+    3541             : 
+    3542             :     // transform the twist into the header's frame
+    3543             :     {
+    3544             :       // the velocity from the odometry
+    3545           0 :       geometry_msgs::Vector3Stamped speed_child_frame;
+    3546           0 :       speed_child_frame.header.frame_id = odom->child_frame_id;
+    3547           0 :       speed_child_frame.header.stamp    = odom->header.stamp;
+    3548           0 :       speed_child_frame.vector.x        = odom->twist.twist.linear.x;
+    3549           0 :       speed_child_frame.vector.y        = odom->twist.twist.linear.y;
+    3550           0 :       speed_child_frame.vector.z        = odom->twist.twist.linear.z;
+    3551             : 
+    3552           0 :       auto res = transformer_->transformSingle(speed_child_frame, odom->header.frame_id);
+    3553             : 
+    3554           0 :       if (res) {
+    3555           0 :         uav_state_.velocity.linear.x = res.value().vector.x;
+    3556           0 :         uav_state_.velocity.linear.y = res.value().vector.y;
+    3557           0 :         uav_state_.velocity.linear.z = res.value().vector.z;
+    3558             :       } else {
+    3559           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: could not transform the odometry speed from '%s' to '%s'", odom->child_frame_id.c_str(),
+    3560             :                            odom->header.frame_id.c_str());
+    3561           0 :         return;
+    3562             :       }
+    3563             :     }
+    3564             : 
+    3565             :     // calculate the euler angles
+    3566           0 :     std::tie(uav_roll_, uav_pitch_, uav_yaw_) = mrs_lib::AttitudeConverter(odom->pose.pose.orientation);
+    3567             : 
+    3568             :     try {
+    3569           0 :       uav_heading_ = mrs_lib::AttitudeConverter(odom->pose.pose.orientation).getHeading();
+    3570             :     }
+    3571           0 :     catch (...) {
+    3572           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: could not calculate UAV heading");
+    3573             :     }
+    3574             : 
+    3575           0 :     transformer_->setDefaultFrame(odom->header.frame_id);
+    3576             : 
+    3577           0 :     got_uav_state_ = true;
+    3578             :   }
+    3579             : 
+    3580             :   // run the control loop asynchronously in an OneShotTimer
+    3581             :   // but only if its not already running
+    3582           0 :   if (!running_async_control_) {
+    3583             : 
+    3584           0 :     running_async_control_ = true;
+    3585             : 
+    3586           0 :     async_control_result_ = std::async(std::launch::async, &ControlManager::asyncControl, this);
+    3587             :   }
+    3588             : }
+    3589             : 
+    3590             : //}
+    3591             : 
+    3592             : /* //{ callbackUavState() */
+    3593             : 
+    3594        8944 : void ControlManager::callbackUavState(const mrs_msgs::UavState::ConstPtr msg) {
+    3595             : 
+    3596        8944 :   if (!is_initialized_)
+    3597         658 :     return;
+    3598             : 
+    3599       17888 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackUavState");
+    3600       17888 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackUavState", scope_timer_logger_, scope_timer_enabled_);
+    3601             : 
+    3602        8944 :   mrs_msgs::UavStateConstPtr uav_state = msg;
+    3603             : 
+    3604             :   // | ------------------ check for time stamp ------------------ |
+    3605             : 
+    3606             :   {
+    3607        8944 :     std::scoped_lock lock(mutex_uav_state_);
+    3608             : 
+    3609        8944 :     if (uav_state_.header.stamp == uav_state->header.stamp) {
+    3610         658 :       return;
+    3611             :     }
+    3612             :   }
+    3613             : 
+    3614             :   // | --------------------- check for nans --------------------- |
+    3615             : 
+    3616        8286 :   if (!validateUavState(*uav_state, "ControlManager", "uav_state")) {
+    3617           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: incoming 'uav_state' contains invalid values, throwing it away");
+    3618           0 :     return;
+    3619             :   }
+    3620             : 
+    3621             :   // | -------------------- check for hiccups ------------------- |
+    3622             : 
+    3623             :   /* hickup detection //{ */
+    3624             : 
+    3625        8286 :   double alpha               = 0.99;
+    3626        8286 :   double alpha2              = 0.666;
+    3627        8286 :   double uav_state_count_lim = 1000;
+    3628             : 
+    3629        8286 :   double uav_state_dt = (ros::Time::now() - previous_uav_state_.header.stamp).toSec();
+    3630             : 
+    3631             :   // belive only reasonable numbers
+    3632        8286 :   if (uav_state_dt <= 1.0) {
+    3633             : 
+    3634        8272 :     uav_state_avg_dt_ = alpha * uav_state_avg_dt_ + (1 - alpha) * uav_state_dt;
+    3635             : 
+    3636        8272 :     if (uav_state_count_ < uav_state_count_lim) {
+    3637        6722 :       uav_state_count_++;
+    3638             :     }
+    3639             :   }
+    3640             : 
+    3641        8286 :   if (uav_state_count_ == uav_state_count_lim) {
+    3642             : 
+    3643             :     /* ROS_INFO_STREAM("[ControlManager]: uav_state_dt = " << uav_state_dt); */
+    3644             : 
+    3645        1553 :     if (uav_state_dt < uav_state_avg_dt_ && uav_state_dt > 0.0001) {
+    3646             : 
+    3647        1311 :       uav_state_hiccup_factor_ = alpha2 * uav_state_hiccup_factor_ + (1 - alpha2) * (uav_state_avg_dt_ / uav_state_dt);
+    3648             : 
+    3649         242 :     } else if (uav_state_avg_dt_ > 0.0001) {
+    3650             : 
+    3651         242 :       uav_state_hiccup_factor_ = alpha2 * uav_state_hiccup_factor_ + (1 - alpha2) * (uav_state_dt / uav_state_avg_dt_);
+    3652             :     }
+    3653             : 
+    3654        1553 :     if (uav_state_hiccup_factor_ > 3.141592653) {
+    3655             : 
+    3656             :       /* ROS_ERROR_STREAM_THROTTLE(0.1, "[ControlManager]: hiccup factor = " << uav_state_hiccup_factor_); */
+    3657             : 
+    3658           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: ");
+    3659           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // | ------------------------- WARNING ------------------------ |");
+    3660           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // |                                                            |");
+    3661           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // |            UAV_STATE has a large hiccup factor!            |");
+    3662           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // |           hint, hint: you are probably rosbagging          |");
+    3663           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // |           lot of data or publishing lot of large           |");
+    3664           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // |          messages without mutual nodelet managers.         |");
+    3665           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // |                                                            |");
+    3666           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: // | ------------------------- WARNING ------------------------ |");
+    3667           0 :       ROS_WARN_THROTTLE(2.0, "[ControlManager]: ");
+    3668             :     }
+    3669             :   }
+    3670             : 
+    3671             :   //}
+    3672             : 
+    3673             :   // | ---------------------- frame switch ---------------------- |
+    3674             : 
+    3675             :   /* frame switch //{ */
+    3676             : 
+    3677             :   // | ----- check for change in odometry frame of reference ---- |
+    3678             : 
+    3679        8286 :   if (got_uav_state_) {
+    3680             : 
+    3681        8279 :     if (uav_state->estimator_iteration != uav_state_.estimator_iteration) {
+    3682             : 
+    3683           0 :       ROS_INFO("[ControlManager]: detecting switch of odometry frame");
+    3684             :       {
+    3685           0 :         std::scoped_lock lock(mutex_uav_state_);
+    3686             : 
+    3687           0 :         ROS_INFO("[ControlManager]: odometry before switch: x=%.2f, y=%.2f, z=%.2f, heading=%.2f", uav_state_.pose.position.x, uav_state_.pose.position.y,
+    3688             :                  uav_state_.pose.position.z, uav_heading_);
+    3689             :       }
+    3690             : 
+    3691           0 :       odometry_switch_in_progress_ = true;
+    3692             : 
+    3693             :       // we have to stop safety timer, otherwise it will interfere
+    3694           0 :       ROS_DEBUG("[ControlManager]: stopping the safety timer");
+    3695           0 :       timer_safety_.stop();
+    3696           0 :       ROS_DEBUG("[ControlManager]: safety timer stopped");
+    3697             : 
+    3698             :       // wait for the safety timer to stop if its running
+    3699           0 :       while (running_safety_timer_) {
+    3700             : 
+    3701           0 :         ROS_DEBUG("[ControlManager]: waiting for safety timer to finish");
+    3702           0 :         ros::Duration wait(0.001);
+    3703           0 :         wait.sleep();
+    3704             : 
+    3705           0 :         if (!running_safety_timer_) {
+    3706           0 :           ROS_DEBUG("[ControlManager]: safety timer finished");
+    3707           0 :           break;
+    3708             :         }
+    3709             :       }
+    3710             : 
+    3711             :       // we have to also for the oneshot control timer to finish
+    3712           0 :       while (running_async_control_) {
+    3713             : 
+    3714           0 :         ROS_DEBUG("[ControlManager]: waiting for control timer to finish");
+    3715           0 :         ros::Duration wait(0.001);
+    3716           0 :         wait.sleep();
+    3717             : 
+    3718           0 :         if (!running_async_control_) {
+    3719           0 :           ROS_DEBUG("[ControlManager]: control timer finished");
+    3720           0 :           break;
+    3721             :         }
+    3722             :       }
+    3723             : 
+    3724             :       {
+    3725           0 :         std::scoped_lock lock(mutex_controller_list_, mutex_tracker_list_);
+    3726             : 
+    3727           0 :         tracker_list_[active_tracker_idx_]->switchOdometrySource(*uav_state);
+    3728           0 :         controller_list_[active_controller_idx_]->switchOdometrySource(*uav_state);
+    3729             :       }
+    3730             :     }
+    3731             :   }
+    3732             : 
+    3733             :   //}
+    3734             : 
+    3735             :   // --------------------------------------------------------------
+    3736             :   // |           copy the UavState message for later use          |
+    3737             :   // --------------------------------------------------------------
+    3738             : 
+    3739             :   {
+    3740        8286 :     std::scoped_lock lock(mutex_uav_state_);
+    3741             : 
+    3742        8286 :     previous_uav_state_ = uav_state_;
+    3743             : 
+    3744        8286 :     uav_state_ = *uav_state;
+    3745             : 
+    3746        8286 :     std::tie(uav_roll_, uav_pitch_, uav_yaw_) = mrs_lib::AttitudeConverter(uav_state_.pose.orientation);
+    3747             : 
+    3748             :     try {
+    3749        8286 :       uav_heading_ = mrs_lib::AttitudeConverter(uav_state_.pose.orientation).getHeading();
+    3750             :     }
+    3751           0 :     catch (...) {
+    3752           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: could not calculate UAV heading, not updating it");
+    3753             :     }
+    3754             : 
+    3755        8286 :     transformer_->setDefaultFrame(uav_state->header.frame_id);
+    3756             : 
+    3757        8286 :     got_uav_state_ = true;
+    3758             :   }
+    3759             : 
+    3760             :   // run the control loop asynchronously in an OneShotTimer
+    3761             :   // but only if its not already running
+    3762        8286 :   if (!running_async_control_) {
+    3763             : 
+    3764        8285 :     running_async_control_ = true;
+    3765             : 
+    3766        8285 :     async_control_result_ = std::async(std::launch::async, &ControlManager::asyncControl, this);
+    3767             :   }
+    3768             : }
+    3769             : 
+    3770             : //}
+    3771             : 
+    3772             : /* //{ callbackGNSS() */
+    3773             : 
+    3774        5320 : void ControlManager::callbackGNSS(const sensor_msgs::NavSatFix::ConstPtr msg) {
+    3775             : 
+    3776        5320 :   if (!is_initialized_)
+    3777           9 :     return;
+    3778             : 
+    3779       15933 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackGNSS");
+    3780       15933 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackGNSS", scope_timer_logger_, scope_timer_enabled_);
+    3781             : 
+    3782        5311 :   transformer_->setLatLon(msg->latitude, msg->longitude);
+    3783             : }
+    3784             : 
+    3785             : //}
+    3786             : 
+    3787             : /* callbackJoystick() //{ */
+    3788             : 
+    3789           0 : void ControlManager::callbackJoystick(const sensor_msgs::Joy::ConstPtr msg) {
+    3790             : 
+    3791           0 :   if (!is_initialized_)
+    3792           0 :     return;
+    3793             : 
+    3794           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackJoystick");
+    3795           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackJoystick", scope_timer_logger_, scope_timer_enabled_);
+    3796             : 
+    3797             :   // copy member variables
+    3798           0 :   auto active_tracker_idx    = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    3799           0 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    3800             : 
+    3801           0 :   sensor_msgs::JoyConstPtr joystick_data = msg;
+    3802             : 
+    3803             :   // TODO check if the array is smaller than the largest idx
+    3804           0 :   if (joystick_data->buttons.size() == 0 || joystick_data->axes.size() == 0) {
+    3805           0 :     return;
+    3806             :   }
+    3807             : 
+    3808             :   // | ---- switching back to fallback tracker and controller --- |
+    3809             : 
+    3810             :   // if any of the A, B, X, Y buttons are pressed when flying with joystick, switch back to fallback controller and tracker
+    3811           0 :   if ((joystick_data->buttons[_channel_A_] == 1 || joystick_data->buttons[_channel_B_] == 1 || joystick_data->buttons[_channel_X_] == 1 ||
+    3812           0 :        joystick_data->buttons[_channel_Y_] == 1) &&
+    3813           0 :       active_tracker_idx == _joystick_tracker_idx_ && active_controller_idx == _joystick_controller_idx_) {
+    3814             : 
+    3815           0 :     ROS_INFO("[ControlManager]: switching from joystick to normal control");
+    3816             : 
+    3817           0 :     switchTracker(_joystick_fallback_tracker_name_);
+    3818           0 :     switchController(_joystick_fallback_controller_name_);
+    3819             : 
+    3820           0 :     joystick_goto_enabled_ = false;
+    3821             :   }
+    3822             : 
+    3823             :   // | ------- joystick control activation ------- |
+    3824             : 
+    3825             :   // if start button was pressed
+    3826           0 :   if (joystick_data->buttons[_channel_start_] == 1) {
+    3827             : 
+    3828           0 :     if (!joystick_start_pressed_) {
+    3829             : 
+    3830           0 :       ROS_INFO("[ControlManager]: joystick start button pressed");
+    3831             : 
+    3832           0 :       joystick_start_pressed_    = true;
+    3833           0 :       joystick_start_press_time_ = ros::Time::now();
+    3834             :     }
+    3835             : 
+    3836           0 :   } else if (joystick_start_pressed_) {
+    3837             : 
+    3838           0 :     ROS_INFO("[ControlManager]: joystick start button released");
+    3839             : 
+    3840           0 :     joystick_start_pressed_    = false;
+    3841           0 :     joystick_start_press_time_ = ros::Time(0);
+    3842             :   }
+    3843             : 
+    3844             :   // | ---------------- Joystick goto activation ---------------- |
+    3845             : 
+    3846             :   // if back button was pressed
+    3847           0 :   if (joystick_data->buttons[_channel_back_] == 1) {
+    3848             : 
+    3849           0 :     if (!joystick_back_pressed_) {
+    3850             : 
+    3851           0 :       ROS_INFO("[ControlManager]: joystick back button pressed");
+    3852             : 
+    3853           0 :       joystick_back_pressed_    = true;
+    3854           0 :       joystick_back_press_time_ = ros::Time::now();
+    3855             :     }
+    3856             : 
+    3857           0 :   } else if (joystick_back_pressed_) {
+    3858             : 
+    3859           0 :     ROS_INFO("[ControlManager]: joystick back button released");
+    3860             : 
+    3861           0 :     joystick_back_pressed_    = false;
+    3862           0 :     joystick_back_press_time_ = ros::Time(0);
+    3863             :   }
+    3864             : 
+    3865             :   // | ------------------------ Failsafes ----------------------- |
+    3866             : 
+    3867             :   // if LT and RT buttons are both pressed down
+    3868           0 :   if (joystick_data->axes[_channel_LT_] < -0.99 && joystick_data->axes[_channel_RT_] < -0.99) {
+    3869             : 
+    3870           0 :     if (!joystick_failsafe_pressed_) {
+    3871             : 
+    3872           0 :       ROS_INFO("[ControlManager]: joystick Failsafe pressed");
+    3873             : 
+    3874           0 :       joystick_failsafe_pressed_    = true;
+    3875           0 :       joystick_failsafe_press_time_ = ros::Time::now();
+    3876             :     }
+    3877             : 
+    3878           0 :   } else if (joystick_failsafe_pressed_) {
+    3879             : 
+    3880           0 :     ROS_INFO("[ControlManager]: joystick Failsafe released");
+    3881             : 
+    3882           0 :     joystick_failsafe_pressed_    = false;
+    3883           0 :     joystick_failsafe_press_time_ = ros::Time(0);
+    3884             :   }
+    3885             : 
+    3886             :   // if left and right joypads are both pressed down
+    3887           0 :   if (joystick_data->buttons[_channel_L_joy_] == 1 && joystick_data->buttons[_channel_R_joy_] == 1) {
+    3888             : 
+    3889           0 :     if (!joystick_eland_pressed_) {
+    3890             : 
+    3891           0 :       ROS_INFO("[ControlManager]: joystick eland pressed");
+    3892             : 
+    3893           0 :       joystick_eland_pressed_    = true;
+    3894           0 :       joystick_eland_press_time_ = ros::Time::now();
+    3895             :     }
+    3896             : 
+    3897           0 :   } else if (joystick_eland_pressed_) {
+    3898             : 
+    3899           0 :     ROS_INFO("[ControlManager]: joystick eland released");
+    3900             : 
+    3901           0 :     joystick_eland_pressed_    = false;
+    3902           0 :     joystick_eland_press_time_ = ros::Time(0);
+    3903             :   }
+    3904             : }
+    3905             : 
+    3906             : //}
+    3907             : 
+    3908             : /* //{ callbackHwApiStatus() */
+    3909             : 
+    3910       37869 : void ControlManager::callbackHwApiStatus(const mrs_msgs::HwApiStatus::ConstPtr msg) {
+    3911             : 
+    3912       37869 :   if (!is_initialized_)
+    3913          32 :     return;
+    3914             : 
+    3915      113511 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackHwApiStatus");
+    3916      113511 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackHwApiStatus", scope_timer_logger_, scope_timer_enabled_);
+    3917             : 
+    3918       75674 :   mrs_msgs::HwApiStatusConstPtr state = msg;
+    3919             : 
+    3920             :   // | ------ detect and print the changes in offboard mode ----- |
+    3921       37837 :   if (state->offboard) {
+    3922             : 
+    3923       28132 :     if (!offboard_mode_) {
+    3924           7 :       offboard_mode_          = true;
+    3925           7 :       offboard_mode_was_true_ = true;
+    3926           7 :       ROS_INFO("[ControlManager]: detected: OFFBOARD mode ON");
+    3927             :     }
+    3928             : 
+    3929             :   } else {
+    3930             : 
+    3931        9705 :     if (offboard_mode_) {
+    3932           0 :       offboard_mode_ = false;
+    3933           0 :       ROS_INFO("[ControlManager]: detected: OFFBOARD mode OFF");
+    3934             :     }
+    3935             :   }
+    3936             : 
+    3937             :   // | --------- detect and print the changes in arming --------- |
+    3938       37837 :   if (state->armed == true) {
+    3939             : 
+    3940       27995 :     if (!armed_) {
+    3941           7 :       armed_ = true;
+    3942           7 :       ROS_INFO("[ControlManager]: detected: vehicle ARMED");
+    3943             :     }
+    3944             : 
+    3945             :   } else {
+    3946             : 
+    3947        9842 :     if (armed_) {
+    3948           5 :       armed_ = false;
+    3949           5 :       ROS_INFO("[ControlManager]: detected: vehicle DISARMED");
+    3950             :     }
+    3951             :   }
+    3952             : }
+    3953             : 
+    3954             : //}
+    3955             : 
+    3956             : /* //{ callbackRC() */
+    3957             : 
+    3958        1073 : void ControlManager::callbackRC(const mrs_msgs::HwApiRcChannels::ConstPtr msg) {
+    3959             : 
+    3960        1073 :   if (!is_initialized_)
+    3961           0 :     return;
+    3962             : 
+    3963        3219 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackRC");
+    3964        3219 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackRC", scope_timer_logger_, scope_timer_enabled_);
+    3965             : 
+    3966        2146 :   mrs_msgs::HwApiRcChannelsConstPtr rc = msg;
+    3967             : 
+    3968        1073 :   ROS_INFO_ONCE("[ControlManager]: getting RC channels");
+    3969             : 
+    3970             :   // | ------------------- rc joystic control ------------------- |
+    3971             : 
+    3972             :   // when the switch change its position
+    3973        1073 :   if (_rc_goto_enabled_) {
+    3974             : 
+    3975        1073 :     if (_rc_joystick_channel_ >= int(rc->channels.size())) {
+    3976             : 
+    3977           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: RC joystick activation channel number (%d) is out of range [0-%d]", _rc_joystick_channel_,
+    3978             :                          int(rc->channels.size()));
+    3979             : 
+    3980             :     } else {
+    3981             : 
+    3982        1073 :       bool channel_low  = rc->channels[_rc_joystick_channel_] < (0.5 - RC_DEADBAND) ? true : false;
+    3983        1073 :       bool channel_high = rc->channels[_rc_joystick_channel_] > (0.5 + RC_DEADBAND) ? true : false;
+    3984             : 
+    3985        1073 :       if (channel_low) {
+    3986        1073 :         rc_joystick_channel_was_low_ = true;
+    3987             :       }
+    3988             : 
+    3989             :       // rc control activation
+    3990        1073 :       if (!rc_goto_active_) {
+    3991             : 
+    3992        1073 :         if (rc_joystick_channel_last_value_ < (0.5 - RC_DEADBAND) && channel_high) {
+    3993             : 
+    3994           0 :           if (isFlyingNormally()) {
+    3995             : 
+    3996           0 :             ROS_INFO_THROTTLE(1.0, "[ControlManager]: activating RC joystick");
+    3997             : 
+    3998           0 :             callbacks_enabled_ = false;
+    3999             : 
+    4000           0 :             std_srvs::SetBoolRequest req_goto_out;
+    4001           0 :             req_goto_out.data = false;
+    4002             : 
+    4003           0 :             std_srvs::SetBoolRequest req_enable_callbacks;
+    4004           0 :             req_enable_callbacks.data = callbacks_enabled_;
+    4005             : 
+    4006             :             {
+    4007           0 :               std::scoped_lock lock(mutex_tracker_list_);
+    4008             : 
+    4009             :               // disable callbacks of all trackers
+    4010           0 :               for (int i = 0; i < int(tracker_list_.size()); i++) {
+    4011           0 :                 tracker_list_[i]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    4012             :               }
+    4013             :             }
+    4014             : 
+    4015           0 :             rc_goto_active_ = true;
+    4016             : 
+    4017             :           } else {
+    4018             : 
+    4019           0 :             ROS_WARN_THROTTLE(1.0, "[ControlManager]: can not activate RC joystick, not flying normally");
+    4020           0 :           }
+    4021             : 
+    4022        1073 :         } else if (channel_high && !rc_joystick_channel_was_low_) {
+    4023             : 
+    4024           0 :           ROS_WARN_THROTTLE(1.0, "[ControlManager]: can not activate RC joystick, the switch is ON from the beginning");
+    4025             :         }
+    4026             :       }
+    4027             : 
+    4028             :       // rc control deactivation
+    4029        1073 :       if (rc_goto_active_ && channel_low) {
+    4030             : 
+    4031           0 :         ROS_INFO("[ControlManager]: deactivating RC joystick");
+    4032             : 
+    4033           0 :         callbacks_enabled_ = true;
+    4034             : 
+    4035           0 :         std_srvs::SetBoolRequest req_goto_out;
+    4036           0 :         req_goto_out.data = true;
+    4037             : 
+    4038           0 :         std_srvs::SetBoolRequest req_enable_callbacks;
+    4039           0 :         req_enable_callbacks.data = callbacks_enabled_;
+    4040             : 
+    4041             :         {
+    4042           0 :           std::scoped_lock lock(mutex_tracker_list_);
+    4043             : 
+    4044             :           // enable callbacks of all trackers
+    4045           0 :           for (int i = 0; i < int(tracker_list_.size()); i++) {
+    4046           0 :             tracker_list_[i]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    4047             :           }
+    4048             :         }
+    4049             : 
+    4050           0 :         rc_goto_active_ = false;
+    4051             :       }
+    4052             : 
+    4053             :       // do not forget to update the last... variable
+    4054             :       // only do that if its out of the deadband
+    4055        1073 :       if (channel_high || channel_low) {
+    4056        1073 :         rc_joystick_channel_last_value_ = rc->channels[_rc_joystick_channel_];
+    4057             :       }
+    4058             :     }
+    4059             :   }
+    4060             : 
+    4061             :   // | ------------------------ rc eland ------------------------ |
+    4062        1073 :   if (_rc_escalating_failsafe_enabled_) {
+    4063             : 
+    4064        1073 :     if (_rc_escalating_failsafe_channel_ >= int(rc->channels.size())) {
+    4065             : 
+    4066           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: RC eland channel number (%d) is out of range [0-%d]", _rc_escalating_failsafe_channel_,
+    4067             :                          int(rc->channels.size()));
+    4068             : 
+    4069             :     } else {
+    4070             : 
+    4071        1073 :       if (rc->channels[_rc_escalating_failsafe_channel_] >= _rc_escalating_failsafe_threshold_) {
+    4072             : 
+    4073           0 :         ROS_WARN_THROTTLE(1.0, "[ControlManager]: triggering escalating failsafe by RC");
+    4074             : 
+    4075           0 :         auto [success, message] = escalatingFailsafe();
+    4076             : 
+    4077           0 :         if (success) {
+    4078           0 :           rc_escalating_failsafe_triggered_ = true;
+    4079             :         }
+    4080             :       }
+    4081             :     }
+    4082             :   }
+    4083             : }
+    4084             : 
+    4085             : //}
+    4086             : 
+    4087             : // | --------------------- topic timeouts --------------------- |
+    4088             : 
+    4089             : /* timeoutUavState() //{ */
+    4090             : 
+    4091           0 : void ControlManager::timeoutUavState(const double& missing_for) {
+    4092             : 
+    4093           0 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    4094             : 
+    4095           0 :   if (output_enabled_ && last_control_output.control_output && !failsafe_triggered_) {
+    4096             : 
+    4097             :     // We need to fire up timerFailsafe, which will regularly trigger the controllers
+    4098             :     // in place of the callbackUavState/callbackOdometry().
+    4099             : 
+    4100           0 :     ROS_ERROR_THROTTLE(0.1, "[ControlManager]: not receiving uav_state/odometry for %.3f s, initiating failsafe land", missing_for);
+    4101             : 
+    4102           0 :     failsafe();
+    4103             :   }
+    4104           0 : }
+    4105             : 
+    4106             : //}
+    4107             : 
+    4108             : // | -------------------- service callbacks ------------------- |
+    4109             : 
+    4110             : /* //{ callbackSwitchTracker() */
+    4111             : 
+    4112          16 : bool ControlManager::callbackSwitchTracker(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res) {
+    4113             : 
+    4114          16 :   if (!is_initialized_)
+    4115           0 :     return false;
+    4116             : 
+    4117          16 :   if (failsafe_triggered_ || eland_triggered_) {
+    4118             : 
+    4119           0 :     std::stringstream ss;
+    4120           0 :     ss << "can not switch tracker, eland or failsafe active";
+    4121             : 
+    4122           0 :     res.message = ss.str();
+    4123           0 :     res.success = false;
+    4124             : 
+    4125           0 :     ROS_WARN_STREAM("[ControlManager]: " << ss.str());
+    4126             : 
+    4127           0 :     return true;
+    4128             :   }
+    4129             : 
+    4130          16 :   auto [success, response] = switchTracker(req.value);
+    4131             : 
+    4132          16 :   res.success = success;
+    4133          16 :   res.message = response;
+    4134             : 
+    4135          16 :   return true;
+    4136             : }
+    4137             : 
+    4138             : //}
+    4139             : 
+    4140             : /* callbackSwitchController() //{ */
+    4141             : 
+    4142          15 : bool ControlManager::callbackSwitchController(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res) {
+    4143             : 
+    4144          15 :   if (!is_initialized_)
+    4145           0 :     return false;
+    4146             : 
+    4147          15 :   if (failsafe_triggered_ || eland_triggered_) {
+    4148             : 
+    4149           0 :     std::stringstream ss;
+    4150           0 :     ss << "can not switch controller, eland or failsafe active";
+    4151             : 
+    4152           0 :     res.message = ss.str();
+    4153           0 :     res.success = false;
+    4154             : 
+    4155           0 :     ROS_WARN_STREAM("[ControlManager]: " << ss.str());
+    4156             : 
+    4157           0 :     return true;
+    4158             :   }
+    4159             : 
+    4160          15 :   auto [success, response] = switchController(req.value);
+    4161             : 
+    4162          15 :   res.success = success;
+    4163          15 :   res.message = response;
+    4164             : 
+    4165          15 :   return true;
+    4166             : }
+    4167             : 
+    4168             : //}
+    4169             : 
+    4170             : /* //{ callbackSwitchTracker() */
+    4171             : 
+    4172           0 : bool ControlManager::callbackTrackerResetStatic([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4173             : 
+    4174           0 :   if (!is_initialized_)
+    4175           0 :     return false;
+    4176             : 
+    4177           0 :   std::stringstream message;
+    4178             : 
+    4179           0 :   if (failsafe_triggered_ || eland_triggered_) {
+    4180             : 
+    4181           0 :     message << "can not reset tracker, eland or failsafe active";
+    4182             : 
+    4183           0 :     res.message = message.str();
+    4184           0 :     res.success = false;
+    4185             : 
+    4186           0 :     ROS_WARN_STREAM("[ControlManager]: " << message.str());
+    4187             : 
+    4188           0 :     return true;
+    4189             :   }
+    4190             : 
+    4191             :   // reactivate the current tracker
+    4192             :   {
+    4193           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    4194             : 
+    4195           0 :     std::string tracker_name = _tracker_names_[active_tracker_idx_];
+    4196             : 
+    4197           0 :     bool succ = tracker_list_[active_tracker_idx_]->resetStatic();
+    4198             : 
+    4199           0 :     if (succ) {
+    4200           0 :       message << "the tracker '" << tracker_name << "' was reset";
+    4201           0 :       ROS_INFO_STREAM("[ControlManager]: " << message.str());
+    4202             :     } else {
+    4203           0 :       message << "the tracker '" << tracker_name << "' reset failed!";
+    4204           0 :       ROS_ERROR_STREAM("[ControlManager]: " << message.str());
+    4205             :     }
+    4206             :   }
+    4207             : 
+    4208           0 :   res.message = message.str();
+    4209           0 :   res.success = true;
+    4210             : 
+    4211           0 :   return true;
+    4212             : }
+    4213             : 
+    4214             : //}
+    4215             : 
+    4216             : /* //{ callbackEHover() */
+    4217             : 
+    4218           0 : bool ControlManager::callbackEHover([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4219             : 
+    4220           0 :   if (!is_initialized_)
+    4221           0 :     return false;
+    4222             : 
+    4223           0 :   if (failsafe_triggered_ || eland_triggered_) {
+    4224             : 
+    4225           0 :     std::stringstream ss;
+    4226           0 :     ss << "can not switch controller, eland or failsafe active";
+    4227             : 
+    4228           0 :     res.message = ss.str();
+    4229           0 :     res.success = false;
+    4230             : 
+    4231           0 :     ROS_WARN_STREAM("[ControlManager]: " << ss.str());
+    4232             : 
+    4233           0 :     return true;
+    4234             :   }
+    4235             : 
+    4236           0 :   ROS_WARN_THROTTLE(1.0, "[ControlManager]: ehover trigger by callback");
+    4237             : 
+    4238           0 :   auto [success, message] = ehover();
+    4239             : 
+    4240           0 :   res.success = success;
+    4241           0 :   res.message = message;
+    4242             : 
+    4243           0 :   return true;
+    4244             : }
+    4245             : 
+    4246             : //}
+    4247             : 
+    4248             : /* callbackFailsafe() //{ */
+    4249             : 
+    4250           0 : bool ControlManager::callbackFailsafe([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4251             : 
+    4252           0 :   if (!is_initialized_)
+    4253           0 :     return false;
+    4254             : 
+    4255           0 :   if (failsafe_triggered_) {
+    4256             : 
+    4257           0 :     std::stringstream ss;
+    4258           0 :     ss << "can not activate failsafe, it is already active";
+    4259             : 
+    4260           0 :     res.message = ss.str();
+    4261           0 :     res.success = false;
+    4262             : 
+    4263           0 :     ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    4264             : 
+    4265           0 :     return true;
+    4266             :   }
+    4267             : 
+    4268           0 :   ROS_WARN_THROTTLE(1.0, "[ControlManager]: failsafe triggered by callback");
+    4269             : 
+    4270           0 :   auto [success, message] = failsafe();
+    4271             : 
+    4272           0 :   res.success = success;
+    4273           0 :   res.message = message;
+    4274             : 
+    4275           0 :   return true;
+    4276             : }
+    4277             : 
+    4278             : //}
+    4279             : 
+    4280             : /* callbackFailsafeEscalating() //{ */
+    4281             : 
+    4282           0 : bool ControlManager::callbackFailsafeEscalating([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4283             : 
+    4284           0 :   if (!is_initialized_)
+    4285           0 :     return false;
+    4286             : 
+    4287           0 :   if (_service_escalating_failsafe_enabled_) {
+    4288             : 
+    4289           0 :     ROS_WARN_THROTTLE(1.0, "[ControlManager]: escalating failsafe triggered by callback");
+    4290             : 
+    4291           0 :     auto [success, message] = escalatingFailsafe();
+    4292             : 
+    4293           0 :     res.success = success;
+    4294           0 :     res.message = message;
+    4295             : 
+    4296             :   } else {
+    4297             : 
+    4298           0 :     std::stringstream ss;
+    4299           0 :     ss << "escalating failsafe is disabled";
+    4300             : 
+    4301           0 :     res.success = false;
+    4302           0 :     res.message = ss.str();
+    4303             : 
+    4304           0 :     ROS_WARN_THROTTLE(1.0, "[ControlManager]: %s", ss.str().c_str());
+    4305             :   }
+    4306             : 
+    4307           0 :   return true;
+    4308             : }
+    4309             : 
+    4310             : //}
+    4311             : 
+    4312             : /* //{ callbackELand() */
+    4313             : 
+    4314           1 : bool ControlManager::callbackEland([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4315             : 
+    4316           1 :   if (!is_initialized_)
+    4317           0 :     return false;
+    4318             : 
+    4319           1 :   ROS_WARN_THROTTLE(1.0, "[ControlManager]: eland triggered by callback");
+    4320             : 
+    4321           1 :   auto [success, message] = eland();
+    4322             : 
+    4323           1 :   res.success = success;
+    4324           1 :   res.message = message;
+    4325             : 
+    4326           1 :   return true;
+    4327             : }
+    4328             : 
+    4329             : //}
+    4330             : 
+    4331             : /* //{ callbackParachute() */
+    4332             : 
+    4333           0 : bool ControlManager::callbackParachute([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4334             : 
+    4335           0 :   if (!is_initialized_)
+    4336           0 :     return false;
+    4337             : 
+    4338           0 :   if (!_parachute_enabled_) {
+    4339             : 
+    4340           0 :     std::stringstream ss;
+    4341           0 :     ss << "parachute disabled";
+    4342           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    4343           0 :     res.message = ss.str();
+    4344           0 :     res.success = false;
+    4345             :   }
+    4346             : 
+    4347           0 :   ROS_WARN_THROTTLE(1.0, "[ControlManager]: parachute triggered by callback");
+    4348             : 
+    4349           0 :   auto [success, message] = deployParachute();
+    4350             : 
+    4351           0 :   res.success = success;
+    4352           0 :   res.message = message;
+    4353             : 
+    4354           0 :   return true;
+    4355             : }
+    4356             : 
+    4357             : //}
+    4358             : 
+    4359             : /* //{ callbackToggleOutput() */
+    4360             : 
+    4361           7 : bool ControlManager::callbackToggleOutput(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res) {
+    4362             : 
+    4363           7 :   if (!is_initialized_)
+    4364           0 :     return false;
+    4365             : 
+    4366           7 :   ROS_INFO("[ControlManager]: toggling output by service");
+    4367             : 
+    4368             :   // copy member variables
+    4369          14 :   auto uav_state = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    4370             : 
+    4371          14 :   std::stringstream ss;
+    4372             : 
+    4373           7 :   bool prereq_check = true;
+    4374             : 
+    4375             :   {
+    4376          14 :     mrs_msgs::ReferenceStamped current_coord;
+    4377           7 :     current_coord.header.frame_id      = uav_state.header.frame_id;
+    4378           7 :     current_coord.reference.position.x = uav_state.pose.position.x;
+    4379           7 :     current_coord.reference.position.y = uav_state.pose.position.y;
+    4380             : 
+    4381           7 :     if (!isPointInSafetyArea2d(current_coord)) {
+    4382           0 :       ss << "cannot toggle output, the UAV is outside of the safety area!";
+    4383           0 :       prereq_check = false;
+    4384             :     }
+    4385             :   }
+    4386             : 
+    4387           7 :   if (req.data && (failsafe_triggered_ || eland_triggered_ || rc_escalating_failsafe_triggered_)) {
+    4388           0 :     ss << "cannot toggle output ON, we landed in emergency";
+    4389           0 :     prereq_check = false;
+    4390             :   }
+    4391             : 
+    4392           7 :   if (!sh_hw_api_status_.hasMsg() || (ros::Time::now() - sh_hw_api_status_.lastMsgTime()).toSec() > 1.0) {
+    4393           0 :     ss << "cannot toggle output ON, missing HW API status!";
+    4394           0 :     prereq_check = false;
+    4395             :   }
+    4396             : 
+    4397           7 :   if (bumper_enabled_ && !sh_bumper_.hasMsg()) {
+    4398           0 :     ss << "cannot toggle output ON, missing bumper data!";
+    4399           0 :     prereq_check = false;
+    4400             :   }
+    4401             : 
+    4402           7 :   if (!prereq_check) {
+    4403             : 
+    4404           0 :     res.message = ss.str();
+    4405           0 :     res.success = false;
+    4406             : 
+    4407           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    4408             : 
+    4409           0 :     return false;
+    4410             : 
+    4411             :   } else {
+    4412             : 
+    4413           7 :     toggleOutput(req.data);
+    4414             : 
+    4415           7 :     ss << "Output: " << (output_enabled_ ? "ON" : "OFF");
+    4416           7 :     res.message = ss.str();
+    4417           7 :     res.success = true;
+    4418             : 
+    4419           7 :     ROS_INFO_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    4420             : 
+    4421           7 :     publishDiagnostics();
+    4422             : 
+    4423           7 :     return true;
+    4424             :   }
+    4425             : }
+    4426             : 
+    4427             : //}
+    4428             : 
+    4429             : /* callbackArm() //{ */
+    4430             : 
+    4431           1 : bool ControlManager::callbackArm(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res) {
+    4432             : 
+    4433           1 :   if (!is_initialized_)
+    4434           0 :     return false;
+    4435             : 
+    4436           1 :   ROS_INFO("[ControlManager]: arming by service");
+    4437             : 
+    4438           2 :   std::stringstream ss;
+    4439             : 
+    4440           1 :   if (failsafe_triggered_ || eland_triggered_) {
+    4441             : 
+    4442           0 :     ss << "can not " << (req.data ? "arm" : "disarm") << ", eland or failsafe active";
+    4443             : 
+    4444           0 :     res.message = ss.str();
+    4445           0 :     res.success = false;
+    4446             : 
+    4447           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    4448             : 
+    4449           0 :     return true;
+    4450             :   }
+    4451             : 
+    4452           1 :   if (req.data) {
+    4453             : 
+    4454           0 :     ss << "this service is not allowed to arm the UAV";
+    4455           0 :     res.success = false;
+    4456           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    4457             : 
+    4458             :   } else {
+    4459             : 
+    4460           2 :     auto [success, message] = arming(false);
+    4461             : 
+    4462           1 :     if (success) {
+    4463             : 
+    4464           1 :       ss << "disarmed";
+    4465           1 :       res.success = true;
+    4466           1 :       ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    4467             : 
+    4468             :     } else {
+    4469             : 
+    4470           0 :       ss << "could not disarm: " << message;
+    4471           0 :       res.success = false;
+    4472           0 :       ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    4473             :     }
+    4474             :   }
+    4475             : 
+    4476           1 :   res.message = ss.str();
+    4477             : 
+    4478           1 :   return true;
+    4479             : }
+    4480             : 
+    4481             : //}
+    4482             : 
+    4483             : /* //{ callbackEnableCallbacks() */
+    4484             : 
+    4485           1 : bool ControlManager::callbackEnableCallbacks(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res) {
+    4486             : 
+    4487           1 :   if (!is_initialized_)
+    4488           0 :     return false;
+    4489             : 
+    4490           1 :   setCallbacks(req.data);
+    4491             : 
+    4492           1 :   std::stringstream ss;
+    4493             : 
+    4494           1 :   ss << "callbacks " << (callbacks_enabled_ ? "enabled" : "disabled");
+    4495             : 
+    4496           1 :   res.message = ss.str();
+    4497           1 :   res.success = true;
+    4498             : 
+    4499           1 :   ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    4500             : 
+    4501           1 :   return true;
+    4502             : }
+    4503             : 
+    4504             : //}
+    4505             : 
+    4506             : /* callbackSetConstraints() //{ */
+    4507             : 
+    4508           7 : bool ControlManager::callbackSetConstraints(mrs_msgs::DynamicsConstraintsSrv::Request& req, mrs_msgs::DynamicsConstraintsSrv::Response& res) {
+    4509             : 
+    4510           7 :   if (!is_initialized_) {
+    4511           0 :     res.message = "not initialized";
+    4512           0 :     res.success = false;
+    4513           0 :     return true;
+    4514             :   }
+    4515             : 
+    4516             :   {
+    4517          14 :     std::scoped_lock lock(mutex_constraints_);
+    4518             : 
+    4519           7 :     current_constraints_ = req;
+    4520             : 
+    4521           7 :     auto enforced = enforceControllersConstraints(current_constraints_);
+    4522             : 
+    4523           7 :     if (enforced) {
+    4524           0 :       sanitized_constraints_      = enforced.value();
+    4525           0 :       constraints_being_enforced_ = true;
+    4526             :     } else {
+    4527           7 :       sanitized_constraints_      = req;
+    4528           7 :       constraints_being_enforced_ = false;
+    4529             :     }
+    4530             : 
+    4531           7 :     got_constraints_ = true;
+    4532             : 
+    4533           7 :     setConstraintsToControllers(current_constraints_);
+    4534           7 :     setConstraintsToTrackers(sanitized_constraints_);
+    4535             :   }
+    4536             : 
+    4537           7 :   res.message = "setting constraints";
+    4538           7 :   res.success = true;
+    4539             : 
+    4540           7 :   return true;
+    4541             : }
+    4542             : 
+    4543             : //}
+    4544             : 
+    4545             : /* //{ callbackEmergencyReference() */
+    4546             : 
+    4547           0 : bool ControlManager::callbackEmergencyReference(mrs_msgs::ReferenceStampedSrv::Request& req, mrs_msgs::ReferenceStampedSrv::Response& res) {
+    4548             : 
+    4549           0 :   if (!is_initialized_)
+    4550           0 :     return false;
+    4551             : 
+    4552           0 :   auto uav_state = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    4553             : 
+    4554           0 :   callbacks_enabled_ = false;
+    4555             : 
+    4556           0 :   mrs_msgs::ReferenceSrvResponse::ConstPtr tracker_response;
+    4557             : 
+    4558           0 :   std::stringstream ss;
+    4559             : 
+    4560             :   // transform the reference to the current frame
+    4561           0 :   mrs_msgs::ReferenceStamped original_reference;
+    4562           0 :   original_reference.header    = req.header;
+    4563           0 :   original_reference.reference = req.reference;
+    4564             : 
+    4565           0 :   auto ret = transformer_->transformSingle(original_reference, uav_state.header.frame_id);
+    4566             : 
+    4567           0 :   if (!ret) {
+    4568             : 
+    4569           0 :     ss << "the emergency reference could not be transformed";
+    4570             : 
+    4571           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    4572           0 :     res.message = ss.str();
+    4573           0 :     res.success = false;
+    4574           0 :     return true;
+    4575             :   }
+    4576             : 
+    4577           0 :   mrs_msgs::ReferenceStamped transformed_reference = ret.value();
+    4578             : 
+    4579           0 :   std_srvs::SetBoolRequest req_enable_callbacks;
+    4580             : 
+    4581           0 :   mrs_msgs::ReferenceSrvRequest req_goto_out;
+    4582           0 :   req_goto_out.reference = transformed_reference.reference;
+    4583             : 
+    4584             :   {
+    4585           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    4586             : 
+    4587             :     // disable callbacks of all trackers
+    4588           0 :     req_enable_callbacks.data = false;
+    4589           0 :     for (int i = 0; i < int(tracker_list_.size()); i++) {
+    4590           0 :       tracker_list_[i]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    4591             :     }
+    4592             : 
+    4593             :     // enable the callbacks for the active tracker
+    4594           0 :     req_enable_callbacks.data = true;
+    4595           0 :     tracker_list_[active_tracker_idx_]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    4596             : 
+    4597             :     // call the setReference()
+    4598           0 :     tracker_response = tracker_list_[active_tracker_idx_]->setReference(
+    4599           0 :         mrs_msgs::ReferenceSrvRequest::ConstPtr(std::make_unique<mrs_msgs::ReferenceSrvRequest>(req_goto_out)));
+    4600             : 
+    4601             :     // disable the callbacks back again
+    4602           0 :     req_enable_callbacks.data = false;
+    4603           0 :     tracker_list_[active_tracker_idx_]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    4604             : 
+    4605           0 :     if (tracker_response != mrs_msgs::ReferenceSrvResponse::Ptr()) {
+    4606           0 :       res.message = tracker_response->message;
+    4607           0 :       res.success = tracker_response->success;
+    4608             :     } else {
+    4609           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'setReference()' function!";
+    4610           0 :       res.message = ss.str();
+    4611           0 :       res.success = false;
+    4612             :     }
+    4613             :   }
+    4614             : 
+    4615           0 :   return true;
+    4616             : }
+    4617             : 
+    4618             : //}
+    4619             : 
+    4620             : /* callbackPirouette() //{ */
+    4621             : 
+    4622           0 : bool ControlManager::callbackPirouette([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4623             : 
+    4624           0 :   if (!is_initialized_)
+    4625           0 :     return false;
+    4626             : 
+    4627             :   // copy member variables
+    4628           0 :   auto uav_state = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    4629             : 
+    4630             :   double uav_heading;
+    4631             :   try {
+    4632           0 :     uav_heading = mrs_lib::AttitudeConverter(uav_state.pose.orientation).getHeading();
+    4633             :   }
+    4634           0 :   catch (...) {
+    4635           0 :     std::stringstream ss;
+    4636           0 :     ss << "could not calculate the UAV heading to initialize the pirouette";
+    4637             : 
+    4638           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    4639             : 
+    4640           0 :     res.message = ss.str();
+    4641           0 :     res.success = false;
+    4642             : 
+    4643           0 :     return false;
+    4644             :   }
+    4645             : 
+    4646           0 :   if (_pirouette_enabled_) {
+    4647           0 :     res.success = false;
+    4648           0 :     res.message = "already active";
+    4649           0 :     return true;
+    4650             :   }
+    4651             : 
+    4652           0 :   if (failsafe_triggered_ || eland_triggered_ || rc_escalating_failsafe_triggered_) {
+    4653             : 
+    4654           0 :     std::stringstream ss;
+    4655           0 :     ss << "can not activate the pirouette, eland or failsafe active";
+    4656             : 
+    4657           0 :     res.message = ss.str();
+    4658           0 :     res.success = false;
+    4659             : 
+    4660           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    4661             : 
+    4662           0 :     return true;
+    4663             :   }
+    4664             : 
+    4665           0 :   _pirouette_enabled_ = true;
+    4666             : 
+    4667           0 :   setCallbacks(false);
+    4668             : 
+    4669           0 :   pirouette_initial_heading_ = uav_heading;
+    4670           0 :   pirouette_iterator_        = 0;
+    4671           0 :   timer_pirouette_.start();
+    4672             : 
+    4673           0 :   res.success = true;
+    4674           0 :   res.message = "activated";
+    4675             : 
+    4676           0 :   return true;
+    4677             : }
+    4678             : 
+    4679             : //}
+    4680             : 
+    4681             : /* callbackUseJoystick() //{ */
+    4682             : 
+    4683           0 : bool ControlManager::callbackUseJoystick([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4684             : 
+    4685           0 :   if (!is_initialized_) {
+    4686           0 :     return false;
+    4687             :   }
+    4688             : 
+    4689           0 :   std::stringstream ss;
+    4690             : 
+    4691             :   {
+    4692           0 :     auto [success, response] = switchTracker(_joystick_tracker_name_);
+    4693             : 
+    4694           0 :     if (!success) {
+    4695             : 
+    4696           0 :       ss << "switching to '" << _joystick_tracker_name_ << "' was unsuccessfull: '" << response << "'";
+    4697           0 :       ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    4698             : 
+    4699           0 :       res.success = false;
+    4700           0 :       res.message = ss.str();
+    4701             : 
+    4702           0 :       return true;
+    4703             :     }
+    4704             :   }
+    4705             : 
+    4706           0 :   auto [success, response] = switchController(_joystick_controller_name_);
+    4707             : 
+    4708           0 :   if (!success) {
+    4709             : 
+    4710           0 :     ss << "switching to '" << _joystick_controller_name_ << "' was unsuccessfull: '" << response << "'";
+    4711           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    4712             : 
+    4713           0 :     res.success = false;
+    4714           0 :     res.message = ss.str();
+    4715             : 
+    4716             :     // switch back to hover tracker
+    4717           0 :     switchTracker(_ehover_tracker_name_);
+    4718             : 
+    4719             :     // switch back to safety controller
+    4720           0 :     switchController(_eland_controller_name_);
+    4721             : 
+    4722           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    4723             : 
+    4724           0 :     return true;
+    4725             :   }
+    4726             : 
+    4727           0 :   ss << "switched to joystick control";
+    4728             : 
+    4729           0 :   res.success = true;
+    4730           0 :   res.message = ss.str();
+    4731             : 
+    4732           0 :   ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    4733             : 
+    4734           0 :   return true;
+    4735             : }
+    4736             : 
+    4737             : //}
+    4738             : 
+    4739             : /* //{ callbackHover() */
+    4740             : 
+    4741           0 : bool ControlManager::callbackHover([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4742             : 
+    4743           0 :   if (!is_initialized_)
+    4744           0 :     return false;
+    4745             : 
+    4746           0 :   auto [success, message] = hover();
+    4747             : 
+    4748           0 :   res.success = success;
+    4749           0 :   res.message = message;
+    4750             : 
+    4751           0 :   return true;
+    4752             : }
+    4753             : 
+    4754             : //}
+    4755             : 
+    4756             : /* //{ callbackStartTrajectoryTracking() */
+    4757             : 
+    4758           0 : bool ControlManager::callbackStartTrajectoryTracking([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4759             : 
+    4760           0 :   if (!is_initialized_)
+    4761           0 :     return false;
+    4762             : 
+    4763           0 :   auto [success, message] = startTrajectoryTracking();
+    4764             : 
+    4765           0 :   res.success = success;
+    4766           0 :   res.message = message;
+    4767             : 
+    4768           0 :   return true;
+    4769             : }
+    4770             : 
+    4771             : //}
+    4772             : 
+    4773             : /* //{ callbackStopTrajectoryTracking() */
+    4774             : 
+    4775           0 : bool ControlManager::callbackStopTrajectoryTracking([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4776             : 
+    4777           0 :   if (!is_initialized_)
+    4778           0 :     return false;
+    4779             : 
+    4780           0 :   auto [success, message] = stopTrajectoryTracking();
+    4781             : 
+    4782           0 :   res.success = success;
+    4783           0 :   res.message = message;
+    4784             : 
+    4785           0 :   return true;
+    4786             : }
+    4787             : 
+    4788             : //}
+    4789             : 
+    4790             : /* //{ callbackResumeTrajectoryTracking() */
+    4791             : 
+    4792           0 : bool ControlManager::callbackResumeTrajectoryTracking([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4793             : 
+    4794           0 :   if (!is_initialized_)
+    4795           0 :     return false;
+    4796             : 
+    4797           0 :   auto [success, message] = resumeTrajectoryTracking();
+    4798             : 
+    4799           0 :   res.success = success;
+    4800           0 :   res.message = message;
+    4801             : 
+    4802           0 :   return true;
+    4803             : }
+    4804             : 
+    4805             : //}
+    4806             : 
+    4807             : /* //{ callbackGotoTrajectoryStart() */
+    4808             : 
+    4809           0 : bool ControlManager::callbackGotoTrajectoryStart([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    4810             : 
+    4811           0 :   if (!is_initialized_)
+    4812           0 :     return false;
+    4813             : 
+    4814           0 :   auto [success, message] = gotoTrajectoryStart();
+    4815             : 
+    4816           0 :   res.success = success;
+    4817           0 :   res.message = message;
+    4818             : 
+    4819           0 :   return true;
+    4820             : }
+    4821             : 
+    4822             : //}
+    4823             : 
+    4824             : /* //{ callbackTransformReference() */
+    4825             : 
+    4826           0 : bool ControlManager::callbackTransformReference(mrs_msgs::TransformReferenceSrv::Request& req, mrs_msgs::TransformReferenceSrv::Response& res) {
+    4827             : 
+    4828           0 :   if (!is_initialized_)
+    4829           0 :     return false;
+    4830             : 
+    4831             :   // transform the reference to the current frame
+    4832           0 :   mrs_msgs::ReferenceStamped transformed_reference = req.reference;
+    4833             : 
+    4834           0 :   if (auto ret = transformer_->transformSingle(transformed_reference, req.frame_id)) {
+    4835             : 
+    4836           0 :     res.reference = ret.value();
+    4837           0 :     res.message   = "transformation successful";
+    4838           0 :     res.success   = true;
+    4839           0 :     return true;
+    4840             : 
+    4841             :   } else {
+    4842             : 
+    4843           0 :     res.message = "the reference could not be transformed";
+    4844           0 :     res.success = false;
+    4845           0 :     return true;
+    4846             :   }
+    4847             : 
+    4848             :   return true;
+    4849             : }
+    4850             : 
+    4851             : //}
+    4852             : 
+    4853             : /* //{ callbackTransformPose() */
+    4854             : 
+    4855           0 : bool ControlManager::callbackTransformPose(mrs_msgs::TransformPoseSrv::Request& req, mrs_msgs::TransformPoseSrv::Response& res) {
+    4856             : 
+    4857           0 :   if (!is_initialized_)
+    4858           0 :     return false;
+    4859             : 
+    4860             :   // transform the reference to the current frame
+    4861           0 :   geometry_msgs::PoseStamped transformed_pose = req.pose;
+    4862             : 
+    4863           0 :   if (auto ret = transformer_->transformSingle(transformed_pose, req.frame_id)) {
+    4864             : 
+    4865           0 :     res.pose    = ret.value();
+    4866           0 :     res.message = "transformation successful";
+    4867           0 :     res.success = true;
+    4868           0 :     return true;
+    4869             : 
+    4870             :   } else {
+    4871             : 
+    4872           0 :     res.message = "the pose could not be transformed";
+    4873           0 :     res.success = false;
+    4874           0 :     return true;
+    4875             :   }
+    4876             : 
+    4877             :   return true;
+    4878             : }
+    4879             : 
+    4880             : //}
+    4881             : 
+    4882             : /* //{ callbackTransformVector3() */
+    4883             : 
+    4884           0 : bool ControlManager::callbackTransformVector3(mrs_msgs::TransformVector3Srv::Request& req, mrs_msgs::TransformVector3Srv::Response& res) {
+    4885             : 
+    4886           0 :   if (!is_initialized_)
+    4887           0 :     return false;
+    4888             : 
+    4889             :   // transform the reference to the current frame
+    4890           0 :   geometry_msgs::Vector3Stamped transformed_vector3 = req.vector;
+    4891             : 
+    4892           0 :   if (auto ret = transformer_->transformSingle(transformed_vector3, req.frame_id)) {
+    4893             : 
+    4894           0 :     res.vector  = ret.value();
+    4895           0 :     res.message = "transformation successful";
+    4896           0 :     res.success = true;
+    4897           0 :     return true;
+    4898             : 
+    4899             :   } else {
+    4900             : 
+    4901           0 :     res.message = "the twist could not be transformed";
+    4902           0 :     res.success = false;
+    4903           0 :     return true;
+    4904             :   }
+    4905             : 
+    4906             :   return true;
+    4907             : }
+    4908             : 
+    4909             : //}
+    4910             : 
+    4911             : /* //{ callbackEnableBumper() */
+    4912             : 
+    4913           0 : bool ControlManager::callbackEnableBumper(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res) {
+    4914             : 
+    4915           0 :   if (!is_initialized_)
+    4916           0 :     return false;
+    4917             : 
+    4918           0 :   bumper_enabled_ = req.data;
+    4919             : 
+    4920           0 :   std::stringstream ss;
+    4921             : 
+    4922           0 :   ss << "bumper " << (bumper_enabled_ ? "enalbed" : "disabled");
+    4923             : 
+    4924           0 :   ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    4925             : 
+    4926           0 :   res.success = true;
+    4927           0 :   res.message = ss.str();
+    4928             : 
+    4929           0 :   return true;
+    4930             : }
+    4931             : 
+    4932             : //}
+    4933             : 
+    4934             : /* //{ callbackUseSafetyArea() */
+    4935             : 
+    4936           0 : bool ControlManager::callbackUseSafetyArea(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res) {
+    4937             : 
+    4938           0 :   if (!is_initialized_)
+    4939           0 :     return false;
+    4940             : 
+    4941           0 :   use_safety_area_ = req.data;
+    4942             : 
+    4943           0 :   std::stringstream ss;
+    4944             : 
+    4945           0 :   ss << "safety area " << (use_safety_area_ ? "enabled" : "disabled");
+    4946             : 
+    4947           0 :   ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    4948             : 
+    4949           0 :   res.success = true;
+    4950           0 :   res.message = ss.str();
+    4951             : 
+    4952           0 :   return true;
+    4953             : }
+    4954             : 
+    4955             : //}
+    4956             : 
+    4957             : /* //{ callbackGetMinZ() */
+    4958             : 
+    4959           0 : bool ControlManager::callbackGetMinZ([[maybe_unused]] mrs_msgs::GetFloat64::Request& req, mrs_msgs::GetFloat64::Response& res) {
+    4960             : 
+    4961           0 :   if (!is_initialized_) {
+    4962           0 :     return false;
+    4963             :   }
+    4964             : 
+    4965           0 :   auto uav_state = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    4966             : 
+    4967           0 :   res.success = true;
+    4968           0 :   res.value   = getMinZ(uav_state.header.frame_id);
+    4969             : 
+    4970           0 :   return true;
+    4971             : }
+    4972             : 
+    4973             : //}
+    4974             : 
+    4975             : /* //{ callbackValidateReference() */
+    4976             : 
+    4977           0 : bool ControlManager::callbackValidateReference(mrs_msgs::ValidateReference::Request& req, mrs_msgs::ValidateReference::Response& res) {
+    4978             : 
+    4979           0 :   if (!is_initialized_) {
+    4980           0 :     res.message = "not initialized";
+    4981           0 :     res.success = false;
+    4982           0 :     return true;
+    4983             :   }
+    4984             : 
+    4985           0 :   if (!validateReference(req.reference.reference, "ControlManager", "reference_for_validation")) {
+    4986           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: NaN detected in variable 'req.reference'!!!");
+    4987           0 :     res.message = "NaNs/infs in input!";
+    4988           0 :     res.success = false;
+    4989           0 :     return true;
+    4990             :   }
+    4991             : 
+    4992             :   // copy member variables
+    4993           0 :   auto uav_state        = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    4994           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    4995             : 
+    4996             :   // transform the reference to the current frame
+    4997           0 :   mrs_msgs::ReferenceStamped original_reference;
+    4998           0 :   original_reference.header    = req.reference.header;
+    4999           0 :   original_reference.reference = req.reference.reference;
+    5000             : 
+    5001           0 :   auto ret = transformer_->transformSingle(original_reference, uav_state.header.frame_id);
+    5002             : 
+    5003           0 :   if (!ret) {
+    5004             : 
+    5005           0 :     ROS_WARN_THROTTLE(1.0, "[ControlManager]: the reference could not be transformed");
+    5006           0 :     res.message = "the reference could not be transformed";
+    5007           0 :     res.success = false;
+    5008           0 :     return true;
+    5009             :   }
+    5010             : 
+    5011           0 :   mrs_msgs::ReferenceStamped transformed_reference = ret.value();
+    5012             : 
+    5013           0 :   if (!isPointInSafetyArea3d(transformed_reference)) {
+    5014           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: reference validation failed, the point is outside of the safety area!");
+    5015           0 :     res.message = "the point is outside of the safety area";
+    5016           0 :     res.success = false;
+    5017           0 :     return true;
+    5018             :   }
+    5019             : 
+    5020           0 :   if (last_tracker_cmd) {
+    5021             : 
+    5022           0 :     mrs_msgs::ReferenceStamped from_point;
+    5023           0 :     from_point.header.frame_id      = uav_state.header.frame_id;
+    5024           0 :     from_point.reference.position.x = last_tracker_cmd->position.x;
+    5025           0 :     from_point.reference.position.y = last_tracker_cmd->position.y;
+    5026           0 :     from_point.reference.position.z = last_tracker_cmd->position.z;
+    5027             : 
+    5028           0 :     if (!isPathToPointInSafetyArea3d(from_point, transformed_reference)) {
+    5029           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: reference validation failed, the path is going outside the safety area!");
+    5030           0 :       res.message = "the path is going outside the safety area";
+    5031           0 :       res.success = false;
+    5032           0 :       return true;
+    5033             :     }
+    5034             :   }
+    5035             : 
+    5036           0 :   res.message = "the reference is ok";
+    5037           0 :   res.success = true;
+    5038           0 :   return true;
+    5039             : }
+    5040             : 
+    5041             : //}
+    5042             : 
+    5043             : /* //{ callbackValidateReference2d() */
+    5044             : 
+    5045         434 : bool ControlManager::callbackValidateReference2d(mrs_msgs::ValidateReference::Request& req, mrs_msgs::ValidateReference::Response& res) {
+    5046             : 
+    5047         434 :   if (!is_initialized_) {
+    5048           0 :     res.message = "not initialized";
+    5049           0 :     res.success = false;
+    5050           0 :     return true;
+    5051             :   }
+    5052             : 
+    5053         434 :   if (!validateReference(req.reference.reference, "ControlManager", "reference_for_validation")) {
+    5054           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: NaN detected in variable 'req.reference'!!!");
+    5055           0 :     res.message = "NaNs/infs in input!";
+    5056           0 :     res.success = false;
+    5057           0 :     return true;
+    5058             :   }
+    5059             : 
+    5060             :   // copy member variables
+    5061         868 :   auto uav_state        = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    5062         868 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5063             : 
+    5064             :   // transform the reference to the current frame
+    5065         868 :   mrs_msgs::ReferenceStamped original_reference;
+    5066         434 :   original_reference.header    = req.reference.header;
+    5067         434 :   original_reference.reference = req.reference.reference;
+    5068             : 
+    5069         868 :   auto ret = transformer_->transformSingle(original_reference, uav_state.header.frame_id);
+    5070             : 
+    5071         434 :   if (!ret) {
+    5072             : 
+    5073          89 :     ROS_WARN_THROTTLE(1.0, "[ControlManager]: the reference could not be transformed");
+    5074          89 :     res.message = "the reference could not be transformed";
+    5075          89 :     res.success = false;
+    5076          89 :     return true;
+    5077             :   }
+    5078             : 
+    5079         690 :   mrs_msgs::ReferenceStamped transformed_reference = ret.value();
+    5080             : 
+    5081         345 :   if (!isPointInSafetyArea2d(transformed_reference)) {
+    5082           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: reference validation failed, the point is outside of the safety area!");
+    5083           0 :     res.message = "the point is outside of the safety area";
+    5084           0 :     res.success = false;
+    5085           0 :     return true;
+    5086             :   }
+    5087             : 
+    5088         345 :   if (last_tracker_cmd) {
+    5089             : 
+    5090         157 :     mrs_msgs::ReferenceStamped from_point;
+    5091         157 :     from_point.header.frame_id      = uav_state.header.frame_id;
+    5092         157 :     from_point.reference.position.x = last_tracker_cmd->position.x;
+    5093         157 :     from_point.reference.position.y = last_tracker_cmd->position.y;
+    5094         157 :     from_point.reference.position.z = last_tracker_cmd->position.z;
+    5095             : 
+    5096         157 :     if (!isPathToPointInSafetyArea2d(from_point, transformed_reference)) {
+    5097           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: reference validation failed, the path is going outside the safety area!");
+    5098           0 :       res.message = "the path is going outside the safety area";
+    5099           0 :       res.success = false;
+    5100           0 :       return true;
+    5101             :     }
+    5102             :   }
+    5103             : 
+    5104         345 :   res.message = "the reference is ok";
+    5105         345 :   res.success = true;
+    5106         345 :   return true;
+    5107             : }
+    5108             : 
+    5109             : //}
+    5110             : 
+    5111             : /* //{ callbackValidateReferenceList() */
+    5112             : 
+    5113           0 : bool ControlManager::callbackValidateReferenceList(mrs_msgs::ValidateReferenceList::Request& req, mrs_msgs::ValidateReferenceList::Response& res) {
+    5114             : 
+    5115           0 :   if (!is_initialized_) {
+    5116           0 :     res.message = "not initialized";
+    5117           0 :     return false;
+    5118             :   }
+    5119             : 
+    5120             :   // copy member variables
+    5121           0 :   auto uav_state        = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    5122           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5123             : 
+    5124             :   // get the transformer
+    5125           0 :   auto ret = transformer_->getTransform(uav_state.header.frame_id, req.list.header.frame_id, req.list.header.stamp);
+    5126             : 
+    5127           0 :   if (!ret) {
+    5128             : 
+    5129           0 :     ROS_DEBUG("[ControlManager]: could not find transform for the reference");
+    5130           0 :     res.message = "could not find transform";
+    5131           0 :     return false;
+    5132             :   }
+    5133             : 
+    5134           0 :   geometry_msgs::TransformStamped tf = ret.value();
+    5135             : 
+    5136           0 :   for (int i = 0; i < int(req.list.list.size()); i++) {
+    5137             : 
+    5138           0 :     res.success.push_back(true);
+    5139             : 
+    5140           0 :     mrs_msgs::ReferenceStamped original_reference;
+    5141           0 :     original_reference.header    = req.list.header;
+    5142           0 :     original_reference.reference = req.list.list[i];
+    5143             : 
+    5144           0 :     res.success[i] = validateReference(original_reference.reference, "ControlManager", "reference_list");
+    5145             : 
+    5146           0 :     auto ret = transformer_->transformSingle(original_reference, uav_state.header.frame_id);
+    5147             : 
+    5148           0 :     if (!ret) {
+    5149             : 
+    5150           0 :       ROS_DEBUG("[ControlManager]: the reference could not be transformed");
+    5151           0 :       res.success[i] = false;
+    5152             :     }
+    5153             : 
+    5154           0 :     mrs_msgs::ReferenceStamped transformed_reference = ret.value();
+    5155             : 
+    5156           0 :     if (!isPointInSafetyArea3d(transformed_reference)) {
+    5157           0 :       res.success[i] = false;
+    5158             :     }
+    5159             : 
+    5160           0 :     if (last_tracker_cmd) {
+    5161             : 
+    5162           0 :       mrs_msgs::ReferenceStamped from_point;
+    5163           0 :       from_point.header.frame_id      = uav_state.header.frame_id;
+    5164           0 :       from_point.reference.position.x = last_tracker_cmd->position.x;
+    5165           0 :       from_point.reference.position.y = last_tracker_cmd->position.y;
+    5166           0 :       from_point.reference.position.z = last_tracker_cmd->position.z;
+    5167             : 
+    5168           0 :       if (!isPathToPointInSafetyArea3d(from_point, transformed_reference)) {
+    5169           0 :         res.success[i] = false;
+    5170             :       }
+    5171             :     }
+    5172             :   }
+    5173             : 
+    5174           0 :   res.message = "references were checked";
+    5175           0 :   return true;
+    5176             : }
+    5177             : 
+    5178             : //}
+    5179             : 
+    5180             : // | -------------- setpoint topics and services -------------- |
+    5181             : 
+    5182             : /* //{ callbackReferenceService() */
+    5183             : 
+    5184           0 : bool ControlManager::callbackReferenceService(mrs_msgs::ReferenceStampedSrv::Request& req, mrs_msgs::ReferenceStampedSrv::Response& res) {
+    5185             : 
+    5186           0 :   if (!is_initialized_) {
+    5187           0 :     res.message = "not initialized";
+    5188           0 :     res.success = false;
+    5189           0 :     return true;
+    5190             :   }
+    5191             : 
+    5192           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackReferenceService");
+    5193           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackReferenceService", scope_timer_logger_, scope_timer_enabled_);
+    5194             : 
+    5195           0 :   mrs_msgs::ReferenceStamped des_reference;
+    5196           0 :   des_reference.header    = req.header;
+    5197           0 :   des_reference.reference = req.reference;
+    5198             : 
+    5199           0 :   auto [success, message] = setReference(des_reference);
+    5200             : 
+    5201           0 :   res.success = success;
+    5202           0 :   res.message = message;
+    5203             : 
+    5204           0 :   return true;
+    5205             : }
+    5206             : 
+    5207             : //}
+    5208             : 
+    5209             : /* //{ callbackReferenceTopic() */
+    5210             : 
+    5211           0 : void ControlManager::callbackReferenceTopic(const mrs_msgs::ReferenceStamped::ConstPtr msg) {
+    5212             : 
+    5213           0 :   if (!is_initialized_)
+    5214           0 :     return;
+    5215             : 
+    5216           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackReferenceTopic");
+    5217           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackReferenceTopic", scope_timer_logger_, scope_timer_enabled_);
+    5218             : 
+    5219           0 :   setReference(*msg);
+    5220             : }
+    5221             : 
+    5222             : //}
+    5223             : 
+    5224             : /* //{ callbackVelocityReferenceService() */
+    5225             : 
+    5226           0 : bool ControlManager::callbackVelocityReferenceService(mrs_msgs::VelocityReferenceStampedSrv::Request&  req,
+    5227             :                                                       mrs_msgs::VelocityReferenceStampedSrv::Response& res) {
+    5228             : 
+    5229           0 :   if (!is_initialized_) {
+    5230           0 :     res.message = "not initialized";
+    5231           0 :     res.success = false;
+    5232           0 :     return true;
+    5233             :   }
+    5234             : 
+    5235           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackVelocityReferenceService");
+    5236           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackVelocityReferenceService", scope_timer_logger_, scope_timer_enabled_);
+    5237             : 
+    5238           0 :   mrs_msgs::VelocityReferenceStamped des_reference;
+    5239           0 :   des_reference = req.reference;
+    5240             : 
+    5241           0 :   auto [success, message] = setVelocityReference(des_reference);
+    5242             : 
+    5243           0 :   res.success = success;
+    5244           0 :   res.message = message;
+    5245             : 
+    5246           0 :   return true;
+    5247             : }
+    5248             : 
+    5249             : //}
+    5250             : 
+    5251             : /* //{ callbackVelocityReferenceTopic() */
+    5252             : 
+    5253           0 : void ControlManager::callbackVelocityReferenceTopic(const mrs_msgs::VelocityReferenceStamped::ConstPtr msg) {
+    5254             : 
+    5255           0 :   if (!is_initialized_)
+    5256           0 :     return;
+    5257             : 
+    5258           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackVelocityReferenceTopic");
+    5259           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackVelocityReferenceTopic", scope_timer_logger_, scope_timer_enabled_);
+    5260             : 
+    5261           0 :   setVelocityReference(*msg);
+    5262             : }
+    5263             : 
+    5264             : //}
+    5265             : 
+    5266             : /* //{ callbackTrajectoryReferenceService() */
+    5267             : 
+    5268           0 : bool ControlManager::callbackTrajectoryReferenceService(mrs_msgs::TrajectoryReferenceSrv::Request& req, mrs_msgs::TrajectoryReferenceSrv::Response& res) {
+    5269             : 
+    5270           0 :   if (!is_initialized_) {
+    5271           0 :     res.message = "not initialized";
+    5272           0 :     res.success = false;
+    5273           0 :     return true;
+    5274             :   }
+    5275             : 
+    5276           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackTrajectoryReferenceService");
+    5277           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackTrajectoryReferenceService", scope_timer_logger_, scope_timer_enabled_);
+    5278             : 
+    5279           0 :   auto [success, message, modified, tracker_names, tracker_successes, tracker_messages] = setTrajectoryReference(req.trajectory);
+    5280             : 
+    5281           0 :   res.success          = success;
+    5282           0 :   res.message          = message;
+    5283           0 :   res.modified         = modified;
+    5284           0 :   res.tracker_names    = tracker_names;
+    5285           0 :   res.tracker_messages = tracker_messages;
+    5286             : 
+    5287           0 :   for (size_t i = 0; i < tracker_successes.size(); i++) {
+    5288           0 :     res.tracker_successes.push_back(tracker_successes[i]);
+    5289             :   }
+    5290             : 
+    5291           0 :   return true;
+    5292             : }
+    5293             : 
+    5294             : //}
+    5295             : 
+    5296             : /* //{ callbackTrajectoryReferenceTopic() */
+    5297             : 
+    5298           0 : void ControlManager::callbackTrajectoryReferenceTopic(const mrs_msgs::TrajectoryReference::ConstPtr msg) {
+    5299             : 
+    5300           0 :   if (!is_initialized_)
+    5301           0 :     return;
+    5302             : 
+    5303           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackTrajectoryReferenceTopic");
+    5304           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackTrajectoryReferenceTopic", scope_timer_logger_, scope_timer_enabled_);
+    5305             : 
+    5306           0 :   setTrajectoryReference(*msg);
+    5307             : }
+    5308             : 
+    5309             : //}
+    5310             : 
+    5311             : // | ------------- human-callable "goto" services ------------- |
+    5312             : 
+    5313             : /* //{ callbackGoto() */
+    5314             : 
+    5315           1 : bool ControlManager::callbackGoto(mrs_msgs::Vec4::Request& req, mrs_msgs::Vec4::Response& res) {
+    5316             : 
+    5317           1 :   if (!is_initialized_) {
+    5318           0 :     res.message = "not initialized";
+    5319           0 :     res.success = false;
+    5320           0 :     return true;
+    5321             :   }
+    5322             : 
+    5323           3 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackGoto");
+    5324           3 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackGoto", scope_timer_logger_, scope_timer_enabled_);
+    5325             : 
+    5326           2 :   mrs_msgs::ReferenceStamped des_reference;
+    5327           1 :   des_reference.header.frame_id      = "";
+    5328           1 :   des_reference.header.stamp         = ros::Time(0);
+    5329           1 :   des_reference.reference.position.x = req.goal[REF_X];
+    5330           1 :   des_reference.reference.position.y = req.goal[REF_Y];
+    5331           1 :   des_reference.reference.position.z = req.goal[REF_Z];
+    5332           1 :   des_reference.reference.heading    = req.goal[REF_HEADING];
+    5333             : 
+    5334           2 :   auto [success, message] = setReference(des_reference);
+    5335             : 
+    5336           1 :   res.success = success;
+    5337           1 :   res.message = message;
+    5338             : 
+    5339           1 :   return true;
+    5340             : }
+    5341             : 
+    5342             : //}
+    5343             : 
+    5344             : /* //{ callbackGotoFcu() */
+    5345             : 
+    5346           0 : bool ControlManager::callbackGotoFcu(mrs_msgs::Vec4::Request& req, mrs_msgs::Vec4::Response& res) {
+    5347             : 
+    5348           0 :   if (!is_initialized_) {
+    5349           0 :     res.message = "not initialized";
+    5350           0 :     res.success = false;
+    5351           0 :     return true;
+    5352             :   }
+    5353             : 
+    5354           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackGotoFcu");
+    5355           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackGotoFcu", scope_timer_logger_, scope_timer_enabled_);
+    5356             : 
+    5357           0 :   mrs_msgs::ReferenceStamped des_reference;
+    5358           0 :   des_reference.header.frame_id      = "fcu_untilted";
+    5359           0 :   des_reference.header.stamp         = ros::Time(0);
+    5360           0 :   des_reference.reference.position.x = req.goal[REF_X];
+    5361           0 :   des_reference.reference.position.y = req.goal[REF_Y];
+    5362           0 :   des_reference.reference.position.z = req.goal[REF_Z];
+    5363           0 :   des_reference.reference.heading    = req.goal[REF_HEADING];
+    5364             : 
+    5365           0 :   auto [success, message] = setReference(des_reference);
+    5366             : 
+    5367           0 :   res.success = success;
+    5368           0 :   res.message = message;
+    5369             : 
+    5370           0 :   return true;
+    5371             : }
+    5372             : 
+    5373             : //}
+    5374             : 
+    5375             : /* //{ callbackGotoRelative() */
+    5376             : 
+    5377           2 : bool ControlManager::callbackGotoRelative(mrs_msgs::Vec4::Request& req, mrs_msgs::Vec4::Response& res) {
+    5378             : 
+    5379           2 :   if (!is_initialized_) {
+    5380           0 :     res.message = "not initialized";
+    5381           0 :     res.success = false;
+    5382           0 :     return true;
+    5383             :   }
+    5384             : 
+    5385           6 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackGotoRelative");
+    5386           6 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackGotoRelative", scope_timer_logger_, scope_timer_enabled_);
+    5387             : 
+    5388           4 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5389             : 
+    5390           2 :   if (!last_tracker_cmd) {
+    5391           0 :     res.message = "not flying";
+    5392           0 :     res.success = false;
+    5393           0 :     return true;
+    5394             :   }
+    5395             : 
+    5396           4 :   mrs_msgs::ReferenceStamped des_reference;
+    5397           2 :   des_reference.header.frame_id      = "";
+    5398           2 :   des_reference.header.stamp         = ros::Time(0);
+    5399           2 :   des_reference.reference.position.x = last_tracker_cmd->position.x + req.goal[REF_X];
+    5400           2 :   des_reference.reference.position.y = last_tracker_cmd->position.y + req.goal[REF_Y];
+    5401           2 :   des_reference.reference.position.z = last_tracker_cmd->position.z + req.goal[REF_Z];
+    5402           2 :   des_reference.reference.heading    = last_tracker_cmd->heading + req.goal[REF_HEADING];
+    5403             : 
+    5404           4 :   auto [success, message] = setReference(des_reference);
+    5405             : 
+    5406           2 :   res.success = success;
+    5407           2 :   res.message = message;
+    5408             : 
+    5409           2 :   return true;
+    5410             : }
+    5411             : 
+    5412             : //}
+    5413             : 
+    5414             : /* //{ callbackGotoAltitude() */
+    5415             : 
+    5416           0 : bool ControlManager::callbackGotoAltitude(mrs_msgs::Vec1::Request& req, mrs_msgs::Vec1::Response& res) {
+    5417             : 
+    5418           0 :   if (!is_initialized_) {
+    5419           0 :     res.message = "not initialized";
+    5420           0 :     res.success = false;
+    5421           0 :     return true;
+    5422             :   }
+    5423             : 
+    5424           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackGotoAltitude");
+    5425           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackGotoAltitude", scope_timer_logger_, scope_timer_enabled_);
+    5426             : 
+    5427           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5428             : 
+    5429           0 :   if (!last_tracker_cmd) {
+    5430           0 :     res.message = "not flying";
+    5431           0 :     res.success = false;
+    5432           0 :     return true;
+    5433             :   }
+    5434             : 
+    5435           0 :   mrs_msgs::ReferenceStamped des_reference;
+    5436           0 :   des_reference.header.frame_id      = "";
+    5437           0 :   des_reference.header.stamp         = ros::Time(0);
+    5438           0 :   des_reference.reference.position.x = last_tracker_cmd->position.x;
+    5439           0 :   des_reference.reference.position.y = last_tracker_cmd->position.y;
+    5440           0 :   des_reference.reference.position.z = req.goal;
+    5441           0 :   des_reference.reference.heading    = last_tracker_cmd->heading;
+    5442             : 
+    5443           0 :   auto [success, message] = setReference(des_reference);
+    5444             : 
+    5445           0 :   res.success = success;
+    5446           0 :   res.message = message;
+    5447             : 
+    5448           0 :   return true;
+    5449             : }
+    5450             : 
+    5451             : //}
+    5452             : 
+    5453             : /* //{ callbackSetHeading() */
+    5454             : 
+    5455           0 : bool ControlManager::callbackSetHeading(mrs_msgs::Vec1::Request& req, mrs_msgs::Vec1::Response& res) {
+    5456             : 
+    5457           0 :   if (!is_initialized_) {
+    5458           0 :     res.message = "not initialized";
+    5459           0 :     res.success = false;
+    5460           0 :     return true;
+    5461             :   }
+    5462             : 
+    5463           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackSetHeading");
+    5464           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackSetHeading", scope_timer_logger_, scope_timer_enabled_);
+    5465             : 
+    5466           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5467             : 
+    5468           0 :   if (!last_tracker_cmd) {
+    5469           0 :     res.message = "not flying";
+    5470           0 :     res.success = false;
+    5471           0 :     return true;
+    5472             :   }
+    5473             : 
+    5474           0 :   mrs_msgs::ReferenceStamped des_reference;
+    5475           0 :   des_reference.header.frame_id      = "";
+    5476           0 :   des_reference.header.stamp         = ros::Time(0);
+    5477           0 :   des_reference.reference.position.x = last_tracker_cmd->position.x;
+    5478           0 :   des_reference.reference.position.y = last_tracker_cmd->position.y;
+    5479           0 :   des_reference.reference.position.z = last_tracker_cmd->position.z;
+    5480           0 :   des_reference.reference.heading    = req.goal;
+    5481             : 
+    5482           0 :   auto [success, message] = setReference(des_reference);
+    5483             : 
+    5484           0 :   res.success = success;
+    5485           0 :   res.message = message;
+    5486             : 
+    5487           0 :   return true;
+    5488             : }
+    5489             : 
+    5490             : //}
+    5491             : 
+    5492             : /* //{ callbackSetHeadingRelative() */
+    5493             : 
+    5494           0 : bool ControlManager::callbackSetHeadingRelative(mrs_msgs::Vec1::Request& req, mrs_msgs::Vec1::Response& res) {
+    5495             : 
+    5496           0 :   if (!is_initialized_) {
+    5497           0 :     res.message = "not initialized";
+    5498           0 :     res.success = false;
+    5499           0 :     return true;
+    5500             :   }
+    5501             : 
+    5502           0 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackSetHeadingRelative");
+    5503           0 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::callbackSetHeadingRelative", scope_timer_logger_, scope_timer_enabled_);
+    5504             : 
+    5505           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5506             : 
+    5507           0 :   if (!last_tracker_cmd) {
+    5508           0 :     res.message = "not flying";
+    5509           0 :     res.success = false;
+    5510           0 :     return true;
+    5511             :   }
+    5512             : 
+    5513           0 :   mrs_msgs::ReferenceStamped des_reference;
+    5514           0 :   des_reference.header.frame_id      = "";
+    5515           0 :   des_reference.header.stamp         = ros::Time(0);
+    5516           0 :   des_reference.reference.position.x = last_tracker_cmd->position.x;
+    5517           0 :   des_reference.reference.position.y = last_tracker_cmd->position.y;
+    5518           0 :   des_reference.reference.position.z = last_tracker_cmd->position.z;
+    5519           0 :   des_reference.reference.heading    = last_tracker_cmd->heading + req.goal;
+    5520             : 
+    5521           0 :   auto [success, message] = setReference(des_reference);
+    5522             : 
+    5523           0 :   res.success = success;
+    5524           0 :   res.message = message;
+    5525             : 
+    5526           0 :   return true;
+    5527             : }
+    5528             : 
+    5529             : //}
+    5530             : 
+    5531             : // --------------------------------------------------------------
+    5532             : // |                          routines                          |
+    5533             : // --------------------------------------------------------------
+    5534             : 
+    5535             : /* setReference() //{ */
+    5536             : 
+    5537           3 : std::tuple<bool, std::string> ControlManager::setReference(const mrs_msgs::ReferenceStamped reference_in) {
+    5538             : 
+    5539           6 :   std::stringstream ss;
+    5540             : 
+    5541           3 :   if (!callbacks_enabled_) {
+    5542           0 :     ss << "can not set the reference, the callbacks are disabled";
+    5543           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5544           0 :     return std::tuple(false, ss.str());
+    5545             :   }
+    5546             : 
+    5547           3 :   if (!validateReference(reference_in.reference, "ControlManager", "reference")) {
+    5548           0 :     ss << "incoming reference is not finite!!!";
+    5549           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5550           0 :     return std::tuple(false, ss.str());
+    5551             :   }
+    5552             : 
+    5553             :   // copy member variables
+    5554           6 :   auto uav_state        = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    5555           6 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5556             : 
+    5557             :   // transform the reference to the current frame
+    5558           6 :   auto ret = transformer_->transformSingle(reference_in, uav_state.header.frame_id);
+    5559             : 
+    5560           3 :   if (!ret) {
+    5561             : 
+    5562           0 :     ss << "the reference could not be transformed";
+    5563           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5564           0 :     return std::tuple(false, ss.str());
+    5565             :   }
+    5566             : 
+    5567           6 :   mrs_msgs::ReferenceStamped transformed_reference = ret.value();
+    5568             : 
+    5569             :   // safety area check
+    5570           3 :   if (!isPointInSafetyArea3d(transformed_reference)) {
+    5571           0 :     ss << "failed to set the reference, the point is outside of the safety area!";
+    5572           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5573           0 :     return std::tuple(false, ss.str());
+    5574             :   }
+    5575             : 
+    5576           3 :   if (last_tracker_cmd) {
+    5577             : 
+    5578           3 :     mrs_msgs::ReferenceStamped from_point;
+    5579           3 :     from_point.header.frame_id      = uav_state.header.frame_id;
+    5580           3 :     from_point.reference.position.x = last_tracker_cmd->position.x;
+    5581           3 :     from_point.reference.position.y = last_tracker_cmd->position.y;
+    5582           3 :     from_point.reference.position.z = last_tracker_cmd->position.z;
+    5583             : 
+    5584           3 :     if (!isPathToPointInSafetyArea3d(from_point, transformed_reference)) {
+    5585           0 :       ss << "failed to set the reference, the path is going outside the safety area!";
+    5586           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5587           0 :       return std::tuple(false, ss.str());
+    5588             :     }
+    5589             :   }
+    5590             : 
+    5591           3 :   mrs_msgs::ReferenceSrvResponse::ConstPtr tracker_response;
+    5592             : 
+    5593             :   // prepare the message for current tracker
+    5594           3 :   mrs_msgs::ReferenceSrvRequest reference_request;
+    5595           3 :   reference_request.reference = transformed_reference.reference;
+    5596             : 
+    5597             :   {
+    5598           6 :     std::scoped_lock lock(mutex_tracker_list_);
+    5599             : 
+    5600           9 :     tracker_response = tracker_list_[active_tracker_idx_]->setReference(
+    5601           9 :         mrs_msgs::ReferenceSrvRequest::ConstPtr(std::make_unique<mrs_msgs::ReferenceSrvRequest>(reference_request)));
+    5602             : 
+    5603           3 :     if (tracker_response != mrs_msgs::ReferenceSrvResponse::Ptr()) {
+    5604             : 
+    5605           6 :       return std::tuple(tracker_response->success, tracker_response->message);
+    5606             : 
+    5607             :     } else {
+    5608             : 
+    5609           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'setReference()' function!";
+    5610           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: failed to set the reference: " << ss.str());
+    5611           0 :       return std::tuple(false, ss.str());
+    5612             :     }
+    5613             :   }
+    5614             : }
+    5615             : 
+    5616             : //}
+    5617             : 
+    5618             : /* setVelocityReference() //{ */
+    5619             : 
+    5620           0 : std::tuple<bool, std::string> ControlManager::setVelocityReference(const mrs_msgs::VelocityReferenceStamped& reference_in) {
+    5621             : 
+    5622           0 :   std::stringstream ss;
+    5623             : 
+    5624           0 :   if (!callbacks_enabled_) {
+    5625           0 :     ss << "can not set the reference, the callbacks are disabled";
+    5626           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5627           0 :     return std::tuple(false, ss.str());
+    5628             :   }
+    5629             : 
+    5630           0 :   if (!validateVelocityReference(reference_in.reference, "ControlManager", "velocity_reference")) {
+    5631           0 :     ss << "velocity command is not valid!";
+    5632           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5633           0 :     return std::tuple(false, ss.str());
+    5634             :   }
+    5635             : 
+    5636             :   {
+    5637           0 :     std::scoped_lock lock(mutex_last_tracker_cmd_);
+    5638             : 
+    5639           0 :     if (!last_tracker_cmd_) {
+    5640           0 :       ss << "could not set velocity command, not flying!";
+    5641           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5642           0 :       return std::tuple(false, ss.str());
+    5643             :     }
+    5644             :   }
+    5645             : 
+    5646             :   // copy member variables
+    5647           0 :   auto uav_state        = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    5648           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5649             : 
+    5650             :   // | -- transform the velocity reference to the current frame - |
+    5651             : 
+    5652           0 :   mrs_msgs::VelocityReferenceStamped transformed_reference = reference_in;
+    5653             : 
+    5654           0 :   auto ret = transformer_->getTransform(reference_in.header.frame_id, uav_state.header.frame_id, reference_in.header.stamp);
+    5655             : 
+    5656           0 :   geometry_msgs::TransformStamped tf;
+    5657             : 
+    5658           0 :   if (!ret) {
+    5659           0 :     ss << "could not find tf from " << reference_in.header.frame_id << " to " << uav_state.header.frame_id;
+    5660           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5661           0 :     return std::tuple(false, ss.str());
+    5662             :   } else {
+    5663           0 :     tf = ret.value();
+    5664             :   }
+    5665             : 
+    5666             :   // transform the velocity
+    5667             :   {
+    5668           0 :     geometry_msgs::Vector3Stamped velocity;
+    5669           0 :     velocity.header   = reference_in.header;
+    5670           0 :     velocity.vector.x = reference_in.reference.velocity.x;
+    5671           0 :     velocity.vector.y = reference_in.reference.velocity.y;
+    5672           0 :     velocity.vector.z = reference_in.reference.velocity.z;
+    5673             : 
+    5674           0 :     auto ret = transformer_->transform(velocity, tf);
+    5675             : 
+    5676           0 :     if (!ret) {
+    5677             : 
+    5678           0 :       ss << "the velocity reference could not be transformed";
+    5679           0 :       ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5680           0 :       return std::tuple(false, ss.str());
+    5681             : 
+    5682             :     } else {
+    5683           0 :       transformed_reference.reference.velocity.x = ret->vector.x;
+    5684           0 :       transformed_reference.reference.velocity.y = ret->vector.y;
+    5685           0 :       transformed_reference.reference.velocity.z = ret->vector.z;
+    5686             :     }
+    5687             :   }
+    5688             : 
+    5689             :   // transform the z and the heading
+    5690             :   {
+    5691           0 :     geometry_msgs::PoseStamped pose;
+    5692           0 :     pose.header           = reference_in.header;
+    5693           0 :     pose.pose.position.x  = 0;
+    5694           0 :     pose.pose.position.y  = 0;
+    5695           0 :     pose.pose.position.z  = reference_in.reference.altitude;
+    5696           0 :     pose.pose.orientation = mrs_lib::AttitudeConverter(0, 0, reference_in.reference.heading);
+    5697             : 
+    5698           0 :     auto ret = transformer_->transform(pose, tf);
+    5699             : 
+    5700           0 :     if (!ret) {
+    5701             : 
+    5702           0 :       ss << "the velocity reference could not be transformed";
+    5703           0 :       ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5704           0 :       return std::tuple(false, ss.str());
+    5705             : 
+    5706             :     } else {
+    5707           0 :       transformed_reference.reference.altitude = ret->pose.position.z;
+    5708           0 :       transformed_reference.reference.heading  = mrs_lib::AttitudeConverter(ret->pose.orientation).getHeading();
+    5709             :     }
+    5710             :   }
+    5711             : 
+    5712             :   // the heading rate doees not need to be transformed
+    5713           0 :   transformed_reference.reference.heading_rate = reference_in.reference.heading_rate;
+    5714             : 
+    5715           0 :   transformed_reference.header.stamp    = tf.header.stamp;
+    5716           0 :   transformed_reference.header.frame_id = transformer_->frame_to(tf);
+    5717             : 
+    5718           0 :   mrs_msgs::ReferenceStamped eqivalent_reference = velocityReferenceToReference(transformed_reference);
+    5719             : 
+    5720           0 :   ROS_DEBUG("[ControlManager]: equivalent reference: %.2f, %.2f, %.2f, %.2f", eqivalent_reference.reference.position.x,
+    5721             :             eqivalent_reference.reference.position.y, eqivalent_reference.reference.position.z, eqivalent_reference.reference.heading);
+    5722             : 
+    5723             :   // safety area check
+    5724           0 :   if (!isPointInSafetyArea3d(eqivalent_reference)) {
+    5725           0 :     ss << "failed to set the reference, the point is outside of the safety area!";
+    5726           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5727           0 :     return std::tuple(false, ss.str());
+    5728             :   }
+    5729             : 
+    5730           0 :   if (last_tracker_cmd) {
+    5731             : 
+    5732           0 :     mrs_msgs::ReferenceStamped from_point;
+    5733           0 :     from_point.header.frame_id      = uav_state.header.frame_id;
+    5734           0 :     from_point.reference.position.x = last_tracker_cmd->position.x;
+    5735           0 :     from_point.reference.position.y = last_tracker_cmd->position.y;
+    5736           0 :     from_point.reference.position.z = last_tracker_cmd->position.z;
+    5737             : 
+    5738           0 :     if (!isPathToPointInSafetyArea3d(from_point, eqivalent_reference)) {
+    5739           0 :       ss << "failed to set the reference, the path is going outside the safety area!";
+    5740           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5741           0 :       return std::tuple(false, ss.str());
+    5742             :     }
+    5743             :   }
+    5744             : 
+    5745           0 :   mrs_msgs::VelocityReferenceSrvResponse::ConstPtr tracker_response;
+    5746             : 
+    5747             :   // prepare the message for current tracker
+    5748           0 :   mrs_msgs::VelocityReferenceSrvRequest reference_request;
+    5749           0 :   reference_request.reference = transformed_reference.reference;
+    5750             : 
+    5751             :   {
+    5752           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    5753             : 
+    5754           0 :     tracker_response = tracker_list_[active_tracker_idx_]->setVelocityReference(
+    5755           0 :         mrs_msgs::VelocityReferenceSrvRequest::ConstPtr(std::make_unique<mrs_msgs::VelocityReferenceSrvRequest>(reference_request)));
+    5756             : 
+    5757           0 :     if (tracker_response != mrs_msgs::VelocityReferenceSrvResponse::Ptr()) {
+    5758             : 
+    5759           0 :       return std::tuple(tracker_response->success, tracker_response->message);
+    5760             : 
+    5761             :     } else {
+    5762             : 
+    5763           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'setVelocityReference()' function!";
+    5764           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: failed to set the velocity reference: " << ss.str());
+    5765           0 :       return std::tuple(false, ss.str());
+    5766             :     }
+    5767             :   }
+    5768             : }
+    5769             : 
+    5770             : //}
+    5771             : 
+    5772             : /* setTrajectoryReference() //{ */
+    5773             : 
+    5774           0 : std::tuple<bool, std::string, bool, std::vector<std::string>, std::vector<bool>, std::vector<std::string>> ControlManager::setTrajectoryReference(
+    5775             :     const mrs_msgs::TrajectoryReference trajectory_in) {
+    5776             : 
+    5777           0 :   auto uav_state        = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    5778           0 :   auto last_tracker_cmd = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    5779             : 
+    5780           0 :   std::stringstream ss;
+    5781             : 
+    5782           0 :   if (!callbacks_enabled_) {
+    5783           0 :     ss << "can not set the reference, the callbacks are disabled";
+    5784           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5785           0 :     return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    5786             :   }
+    5787             : 
+    5788             :   /* validate the size and check for NaNs //{ */
+    5789             : 
+    5790             :   // check for the size 0, which is invalid
+    5791           0 :   if (trajectory_in.points.size() == 0) {
+    5792             : 
+    5793           0 :     ss << "can not load trajectory with size 0";
+    5794           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5795           0 :     return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    5796             :   }
+    5797             : 
+    5798           0 :   for (int i = 0; i < int(trajectory_in.points.size()); i++) {
+    5799             : 
+    5800             :     // check the point for NaN/inf
+    5801           0 :     bool valid = validateReference(trajectory_in.points[i], "ControlManager", "trajectory_in.points[]");
+    5802             : 
+    5803           0 :     if (!valid) {
+    5804             : 
+    5805           0 :       ss << "trajectory contains NaNs/infs.";
+    5806           0 :       ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5807           0 :       return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    5808             :     }
+    5809             :   }
+    5810             : 
+    5811             :   //}
+    5812             : 
+    5813             :   /* publish the debugging topics of the original trajectory //{ */
+    5814             : 
+    5815             :   {
+    5816             : 
+    5817           0 :     geometry_msgs::PoseArray debug_trajectory_out;
+    5818           0 :     debug_trajectory_out.header = trajectory_in.header;
+    5819             : 
+    5820           0 :     debug_trajectory_out.header.frame_id = transformer_->resolveFrame(debug_trajectory_out.header.frame_id);
+    5821             : 
+    5822           0 :     if (debug_trajectory_out.header.stamp == ros::Time(0)) {
+    5823           0 :       debug_trajectory_out.header.stamp = ros::Time::now();
+    5824             :     }
+    5825             : 
+    5826           0 :     for (int i = 0; i < int(trajectory_in.points.size()) - 1; i++) {
+    5827             : 
+    5828           0 :       geometry_msgs::Pose new_pose;
+    5829             : 
+    5830           0 :       new_pose.position.x = trajectory_in.points[i].position.x;
+    5831           0 :       new_pose.position.y = trajectory_in.points[i].position.y;
+    5832           0 :       new_pose.position.z = trajectory_in.points[i].position.z;
+    5833             : 
+    5834           0 :       new_pose.orientation = mrs_lib::AttitudeConverter(0, 0, trajectory_in.points[i].heading);
+    5835             : 
+    5836           0 :       debug_trajectory_out.poses.push_back(new_pose);
+    5837             :     }
+    5838             : 
+    5839           0 :     pub_debug_original_trajectory_poses_.publish(debug_trajectory_out);
+    5840             : 
+    5841           0 :     visualization_msgs::MarkerArray msg_out;
+    5842             : 
+    5843           0 :     visualization_msgs::Marker marker;
+    5844             : 
+    5845           0 :     marker.header = trajectory_in.header;
+    5846             : 
+    5847           0 :     marker.header.frame_id = transformer_->resolveFrame(marker.header.frame_id);
+    5848             : 
+    5849           0 :     if (marker.header.frame_id == "") {
+    5850           0 :       marker.header.frame_id = uav_state.header.frame_id;
+    5851             :     }
+    5852             : 
+    5853           0 :     if (marker.header.stamp == ros::Time(0)) {
+    5854           0 :       marker.header.stamp = ros::Time::now();
+    5855             :     }
+    5856             : 
+    5857           0 :     marker.type             = visualization_msgs::Marker::LINE_LIST;
+    5858           0 :     marker.color.a          = 1;
+    5859           0 :     marker.scale.x          = 0.05;
+    5860           0 :     marker.color.r          = 0;
+    5861           0 :     marker.color.g          = 1;
+    5862           0 :     marker.color.b          = 0;
+    5863           0 :     marker.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+    5864             : 
+    5865           0 :     for (int i = 0; i < int(trajectory_in.points.size()) - 1; i++) {
+    5866             : 
+    5867           0 :       geometry_msgs::Point point1;
+    5868             : 
+    5869           0 :       point1.x = trajectory_in.points[i].position.x;
+    5870           0 :       point1.y = trajectory_in.points[i].position.y;
+    5871           0 :       point1.z = trajectory_in.points[i].position.z;
+    5872             : 
+    5873           0 :       marker.points.push_back(point1);
+    5874             : 
+    5875           0 :       geometry_msgs::Point point2;
+    5876             : 
+    5877           0 :       point2.x = trajectory_in.points[i + 1].position.x;
+    5878           0 :       point2.y = trajectory_in.points[i + 1].position.y;
+    5879           0 :       point2.z = trajectory_in.points[i + 1].position.z;
+    5880             : 
+    5881           0 :       marker.points.push_back(point2);
+    5882             :     }
+    5883             : 
+    5884           0 :     msg_out.markers.push_back(marker);
+    5885             : 
+    5886           0 :     pub_debug_original_trajectory_markers_.publish(msg_out);
+    5887             :   }
+    5888             : 
+    5889             :   //}
+    5890             : 
+    5891           0 :   mrs_msgs::TrajectoryReference processed_trajectory = trajectory_in;
+    5892             : 
+    5893           0 :   int trajectory_size = int(processed_trajectory.points.size());
+    5894             : 
+    5895           0 :   bool trajectory_modified = false;
+    5896             : 
+    5897             :   /* safety area check //{ */
+    5898             : 
+    5899           0 :   if (use_safety_area_) {
+    5900             : 
+    5901           0 :     int last_valid_idx    = 0;
+    5902           0 :     int first_invalid_idx = -1;
+    5903             : 
+    5904           0 :     double min_z = getMinZ(processed_trajectory.header.frame_id);
+    5905           0 :     double max_z = getMaxZ(processed_trajectory.header.frame_id);
+    5906             : 
+    5907           0 :     for (int i = 0; i < trajectory_size; i++) {
+    5908             : 
+    5909           0 :       if (_snap_trajectory_to_safety_area_) {
+    5910             : 
+    5911             :         // saturate the trajectory to min and max Z
+    5912           0 :         if (processed_trajectory.points[i].position.z < min_z) {
+    5913             : 
+    5914           0 :           processed_trajectory.points[i].position.z = min_z;
+    5915           0 :           ROS_WARN_THROTTLE(1.0, "[ControlManager]: the trajectory violates the minimum Z!");
+    5916           0 :           trajectory_modified = true;
+    5917             :         }
+    5918             : 
+    5919           0 :         if (processed_trajectory.points[i].position.z > max_z) {
+    5920             : 
+    5921           0 :           processed_trajectory.points[i].position.z = max_z;
+    5922           0 :           ROS_WARN_THROTTLE(1.0, "[ControlManager]: the trajectory violates the maximum Z!");
+    5923           0 :           trajectory_modified = true;
+    5924             :         }
+    5925             :       }
+    5926             : 
+    5927             :       // check the point against the safety area
+    5928           0 :       mrs_msgs::ReferenceStamped des_reference;
+    5929           0 :       des_reference.header    = processed_trajectory.header;
+    5930           0 :       des_reference.reference = processed_trajectory.points[i];
+    5931             : 
+    5932           0 :       if (!isPointInSafetyArea3d(des_reference)) {
+    5933             : 
+    5934           0 :         ROS_WARN_THROTTLE(1.0, "[ControlManager]: the trajectory contains points outside of the safety area!");
+    5935           0 :         trajectory_modified = true;
+    5936             : 
+    5937             :         // the first invalid point
+    5938           0 :         if (first_invalid_idx == -1) {
+    5939             : 
+    5940           0 :           first_invalid_idx = i;
+    5941             : 
+    5942           0 :           last_valid_idx = i - 1;
+    5943             :         }
+    5944             : 
+    5945             :         // the point is ok
+    5946             :       } else {
+    5947             : 
+    5948             :         // we found a point, which is ok, after finding a point which was not ok
+    5949           0 :         if (first_invalid_idx != -1) {
+    5950             : 
+    5951             :           // special case, we had no valid point so far
+    5952           0 :           if (last_valid_idx == -1) {
+    5953             : 
+    5954           0 :             ss << "the trajectory starts outside of the safety area!";
+    5955           0 :             ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    5956           0 :             return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    5957             : 
+    5958             :             // we have a valid point in the past
+    5959             :           } else {
+    5960             : 
+    5961           0 :             if (!_snap_trajectory_to_safety_area_) {
+    5962           0 :               break;
+    5963             :             }
+    5964             : 
+    5965           0 :             bool interpolation_success = true;
+    5966             : 
+    5967             :             // iterpolate between the last valid point and this new valid point
+    5968           0 :             double angle = atan2((processed_trajectory.points[i].position.y - processed_trajectory.points[last_valid_idx].position.y),
+    5969           0 :                                  (processed_trajectory.points[i].position.x - processed_trajectory.points[last_valid_idx].position.x));
+    5970             : 
+    5971             :             double dist_two_points =
+    5972           0 :                 mrs_lib::geometry::dist(vec2_t(processed_trajectory.points[i].position.x, processed_trajectory.points[i].position.y),
+    5973           0 :                                         vec2_t(processed_trajectory.points[last_valid_idx].position.x, processed_trajectory.points[last_valid_idx].position.y));
+    5974           0 :             double step = dist_two_points / (i - last_valid_idx);
+    5975             : 
+    5976           0 :             for (int j = last_valid_idx; j < i; j++) {
+    5977             : 
+    5978           0 :               mrs_msgs::ReferenceStamped temp_point;
+    5979           0 :               temp_point.header.frame_id      = processed_trajectory.header.frame_id;
+    5980           0 :               temp_point.reference.position.x = processed_trajectory.points[last_valid_idx].position.x + (j - last_valid_idx) * cos(angle) * step;
+    5981           0 :               temp_point.reference.position.y = processed_trajectory.points[last_valid_idx].position.y + (j - last_valid_idx) * sin(angle) * step;
+    5982             : 
+    5983           0 :               if (!isPointInSafetyArea2d(temp_point)) {
+    5984             : 
+    5985           0 :                 interpolation_success = false;
+    5986           0 :                 break;
+    5987             : 
+    5988             :               } else {
+    5989             : 
+    5990           0 :                 processed_trajectory.points[j].position.x = temp_point.reference.position.x;
+    5991           0 :                 processed_trajectory.points[j].position.y = temp_point.reference.position.y;
+    5992             :               }
+    5993             :             }
+    5994             : 
+    5995           0 :             if (!interpolation_success) {
+    5996           0 :               break;
+    5997             :             }
+    5998             :           }
+    5999             : 
+    6000           0 :           first_invalid_idx = -1;
+    6001             :         }
+    6002             :       }
+    6003             :     }
+    6004             : 
+    6005             :     // special case, the trajectory does not end with a valid point
+    6006           0 :     if (first_invalid_idx != -1) {
+    6007             : 
+    6008             :       // super special case, the whole trajectory is invalid
+    6009           0 :       if (first_invalid_idx == 0) {
+    6010             : 
+    6011           0 :         ss << "the whole trajectory is outside of the safety area!";
+    6012           0 :         ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    6013           0 :         return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    6014             : 
+    6015             :         // there is a good portion of the trajectory in the beginning
+    6016             :       } else {
+    6017             : 
+    6018           0 :         trajectory_size = last_valid_idx + 1;
+    6019           0 :         processed_trajectory.points.resize(trajectory_size);
+    6020           0 :         trajectory_modified = true;
+    6021             :       }
+    6022             :     }
+    6023             :   }
+    6024             : 
+    6025           0 :   if (trajectory_size == 0) {
+    6026             : 
+    6027           0 :     ss << "the trajectory happened to be empty after all the checks! This message should not appear!";
+    6028           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    6029           0 :     return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    6030             :   }
+    6031             : 
+    6032             :   //}
+    6033             : 
+    6034             :   /* transform the trajectory to the current control frame //{ */
+    6035             : 
+    6036           0 :   std::optional<geometry_msgs::TransformStamped> tf_traj_state;
+    6037             : 
+    6038           0 :   if (processed_trajectory.header.stamp > ros::Time::now()) {
+    6039           0 :     tf_traj_state = transformer_->getTransform(processed_trajectory.header.frame_id, "", processed_trajectory.header.stamp);
+    6040             :   } else {
+    6041           0 :     tf_traj_state = transformer_->getTransform(processed_trajectory.header.frame_id, "", uav_state_.header.stamp);
+    6042             :   }
+    6043             : 
+    6044           0 :   if (!tf_traj_state) {
+    6045           0 :     ss << "could not create TF transformer for the trajectory";
+    6046           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    6047           0 :     return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    6048             :   }
+    6049             : 
+    6050           0 :   processed_trajectory.header.frame_id = transformer_->frame_to(*tf_traj_state);
+    6051             : 
+    6052           0 :   for (int i = 0; i < trajectory_size; i++) {
+    6053             : 
+    6054           0 :     mrs_msgs::ReferenceStamped trajectory_point;
+    6055           0 :     trajectory_point.header    = processed_trajectory.header;
+    6056           0 :     trajectory_point.reference = processed_trajectory.points[i];
+    6057             : 
+    6058           0 :     auto ret = transformer_->transform(trajectory_point, *tf_traj_state);
+    6059             : 
+    6060           0 :     if (!ret) {
+    6061             : 
+    6062           0 :       ss << "trajectory cannnot be transformed";
+    6063           0 :       ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    6064           0 :       return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    6065             : 
+    6066             :     } else {
+    6067             : 
+    6068             :       // transform the points in the trajectory to the current frame
+    6069           0 :       processed_trajectory.points[i] = ret.value().reference;
+    6070             :     }
+    6071             :   }
+    6072             : 
+    6073             :   //}
+    6074             : 
+    6075           0 :   mrs_msgs::TrajectoryReferenceSrvResponse::ConstPtr response;
+    6076           0 :   mrs_msgs::TrajectoryReferenceSrvRequest            request;
+    6077             : 
+    6078             :   // check for empty trajectory
+    6079           0 :   if (processed_trajectory.points.size() == 0) {
+    6080           0 :     ss << "reference trajectory was processing and it is now empty, this should not happen!";
+    6081           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    6082           0 :     return std::tuple(false, ss.str(), false, std::vector<std::string>(), std::vector<bool>(), std::vector<std::string>());
+    6083             :   }
+    6084             : 
+    6085             :   // prepare the message for current tracker
+    6086           0 :   request.trajectory = processed_trajectory;
+    6087             : 
+    6088             :   bool                     success;
+    6089           0 :   std::string              message;
+    6090             :   bool                     modified;
+    6091           0 :   std::vector<std::string> tracker_names;
+    6092           0 :   std::vector<bool>        tracker_successes;
+    6093           0 :   std::vector<std::string> tracker_messages;
+    6094             : 
+    6095             :   {
+    6096           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    6097             : 
+    6098             :     // set the trajectory to the currently active tracker
+    6099           0 :     response = tracker_list_[active_tracker_idx_]->setTrajectoryReference(
+    6100           0 :         mrs_msgs::TrajectoryReferenceSrvRequest::ConstPtr(std::make_unique<mrs_msgs::TrajectoryReferenceSrvRequest>(request)));
+    6101             : 
+    6102           0 :     tracker_names.push_back(_tracker_names_[active_tracker_idx_]);
+    6103             : 
+    6104           0 :     if (response != mrs_msgs::TrajectoryReferenceSrvResponse::Ptr()) {
+    6105             : 
+    6106           0 :       success  = response->success;
+    6107           0 :       message  = response->message;
+    6108           0 :       modified = response->modified || trajectory_modified;
+    6109           0 :       tracker_successes.push_back(response->success);
+    6110           0 :       tracker_messages.push_back(response->message);
+    6111             : 
+    6112             :     } else {
+    6113             : 
+    6114           0 :       ss << "the active tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'setTrajectoryReference()' function!";
+    6115           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: failed to set the trajectory: " << ss.str());
+    6116             : 
+    6117           0 :       success  = false;
+    6118           0 :       message  = ss.str();
+    6119           0 :       modified = false;
+    6120           0 :       tracker_successes.push_back(false);
+    6121           0 :       tracker_messages.push_back(ss.str());
+    6122             :     }
+    6123             : 
+    6124             :     // set the trajectory to the non-active trackers
+    6125           0 :     for (size_t i = 0; i < tracker_list_.size(); i++) {
+    6126             : 
+    6127           0 :       if (i != active_tracker_idx_) {
+    6128             : 
+    6129           0 :         tracker_names.push_back(_tracker_names_[i]);
+    6130             : 
+    6131           0 :         response = tracker_list_[i]->setTrajectoryReference(
+    6132           0 :             mrs_msgs::TrajectoryReferenceSrvRequest::ConstPtr(std::make_unique<mrs_msgs::TrajectoryReferenceSrvRequest>(request)));
+    6133             : 
+    6134           0 :         if (response != mrs_msgs::TrajectoryReferenceSrvResponse::Ptr()) {
+    6135             : 
+    6136           0 :           tracker_successes.push_back(response->success);
+    6137           0 :           tracker_messages.push_back(response->message);
+    6138             : 
+    6139           0 :           if (response->success) {
+    6140           0 :             std::stringstream ss;
+    6141           0 :             ss << "trajectory loaded to non-active tracker '" << _tracker_names_[i];
+    6142           0 :             ROS_INFO_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    6143             :           }
+    6144             : 
+    6145             :         } else {
+    6146             : 
+    6147           0 :           std::stringstream ss;
+    6148           0 :           ss << "the tracker \"" << _tracker_names_[i] << "\" does not implement setTrajectoryReference()";
+    6149           0 :           tracker_successes.push_back(false);
+    6150           0 :           tracker_messages.push_back(ss.str());
+    6151             :         }
+    6152             :       }
+    6153             :     }
+    6154             :   }
+    6155             : 
+    6156           0 :   return std::tuple(success, message, modified, tracker_names, tracker_successes, tracker_messages);
+    6157             : }
+    6158             : 
+    6159             : //}
+    6160             : 
+    6161             : /* isOffboard() //{ */
+    6162             : 
+    6163           5 : bool ControlManager::isOffboard(void) {
+    6164             : 
+    6165           5 :   if (!sh_hw_api_status_.hasMsg()) {
+    6166           0 :     return false;
+    6167             :   }
+    6168             : 
+    6169           5 :   mrs_msgs::HwApiStatusConstPtr hw_api_status = sh_hw_api_status_.getMsg();
+    6170             : 
+    6171           5 :   return hw_api_status->connected && hw_api_status->offboard;
+    6172             : }
+    6173             : 
+    6174             : //}
+    6175             : 
+    6176             : /* setCallbacks() //{ */
+    6177             : 
+    6178           1 : void ControlManager::setCallbacks(bool in) {
+    6179             : 
+    6180           1 :   callbacks_enabled_ = in;
+    6181             : 
+    6182           1 :   std_srvs::SetBoolRequest req_enable_callbacks;
+    6183           1 :   req_enable_callbacks.data = callbacks_enabled_;
+    6184             : 
+    6185             :   {
+    6186           2 :     std::scoped_lock lock(mutex_tracker_list_);
+    6187             : 
+    6188             :     // set callbacks to all trackers
+    6189           7 :     for (int i = 0; i < int(tracker_list_.size()); i++) {
+    6190           6 :       tracker_list_[i]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    6191             :     }
+    6192             :   }
+    6193           1 : }
+    6194             : 
+    6195             : //}
+    6196             : 
+    6197             : /* publishDiagnostics() //{ */
+    6198             : 
+    6199        1087 : void ControlManager::publishDiagnostics(void) {
+    6200             : 
+    6201        1087 :   if (!is_initialized_) {
+    6202           0 :     return;
+    6203             :   }
+    6204             : 
+    6205        3261 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("publishDiagnostics");
+    6206        3261 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::publishDiagnostics", scope_timer_logger_, scope_timer_enabled_);
+    6207             : 
+    6208        2174 :   std::scoped_lock lock(mutex_diagnostics_);
+    6209             : 
+    6210        2174 :   mrs_msgs::ControlManagerDiagnostics diagnostics_msg;
+    6211             : 
+    6212        1087 :   diagnostics_msg.stamp    = ros::Time::now();
+    6213        1087 :   diagnostics_msg.uav_name = _uav_name_;
+    6214             : 
+    6215        1087 :   diagnostics_msg.desired_uav_state_rate = desired_uav_state_rate_;
+    6216             : 
+    6217        1087 :   diagnostics_msg.output_enabled = output_enabled_;
+    6218             : 
+    6219        1087 :   diagnostics_msg.rc_mode = rc_goto_active_;
+    6220             : 
+    6221             :   {
+    6222        1087 :     std::scoped_lock lock(mutex_tracker_list_, mutex_controller_list_);
+    6223             : 
+    6224        1087 :     diagnostics_msg.flying_normally = isFlyingNormally();
+    6225             :   }
+    6226             : 
+    6227             :   // | ----------------- fill the tracker status ---------------- |
+    6228             : 
+    6229             :   {
+    6230        2174 :     std::scoped_lock lock(mutex_tracker_list_);
+    6231             : 
+    6232        1087 :     mrs_msgs::TrackerStatus tracker_status;
+    6233             : 
+    6234        1087 :     diagnostics_msg.active_tracker = _tracker_names_[active_tracker_idx_];
+    6235        1087 :     diagnostics_msg.tracker_status = tracker_list_[active_tracker_idx_]->getStatus();
+    6236             :   }
+    6237             : 
+    6238             :   // | --------------- fill the controller status --------------- |
+    6239             : 
+    6240             :   {
+    6241        2174 :     std::scoped_lock lock(mutex_controller_list_);
+    6242             : 
+    6243        1087 :     mrs_msgs::ControllerStatus controller_status;
+    6244             : 
+    6245        1087 :     diagnostics_msg.active_controller = _controller_names_[active_controller_idx_];
+    6246        1087 :     diagnostics_msg.controller_status = controller_list_[active_controller_idx_]->getStatus();
+    6247             :   }
+    6248             : 
+    6249             :   // | ------------ fill in the available controllers ----------- |
+    6250             : 
+    6251        6522 :   for (int i = 0; i < int(_controller_names_.size()); i++) {
+    6252        5435 :     if ((_controller_names_[i] != _failsafe_controller_name_) && (_controller_names_[i] != _eland_controller_name_)) {
+    6253        3261 :       diagnostics_msg.available_controllers.push_back(_controller_names_[i]);
+    6254        3261 :       diagnostics_msg.human_switchable_controllers.push_back(controllers_.at(_controller_names_[i]).human_switchable);
+    6255             :     }
+    6256             :   }
+    6257             : 
+    6258             :   // | ------------- fill in the available trackers ------------- |
+    6259             : 
+    6260        7609 :   for (int i = 0; i < int(_tracker_names_.size()); i++) {
+    6261        6522 :     if (_tracker_names_[i] != _null_tracker_name_) {
+    6262        5435 :       diagnostics_msg.available_trackers.push_back(_tracker_names_[i]);
+    6263        5435 :       diagnostics_msg.human_switchable_trackers.push_back(trackers_.at(_tracker_names_[i]).human_switchable);
+    6264             :     }
+    6265             :   }
+    6266             : 
+    6267             :   // | ------------------------- publish ------------------------ |
+    6268             : 
+    6269        1087 :   ph_diagnostics_.publish(diagnostics_msg);
+    6270             : }
+    6271             : 
+    6272             : //}
+    6273             : 
+    6274             : /* setConstraintsToTrackers() //{ */
+    6275             : 
+    6276          24 : void ControlManager::setConstraintsToTrackers(const mrs_msgs::DynamicsConstraintsSrvRequest& constraints) {
+    6277             : 
+    6278          72 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("setConstraintsToTrackers");
+    6279          72 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::setConstraintsToTrackers", scope_timer_logger_, scope_timer_enabled_);
+    6280             : 
+    6281          24 :   mrs_msgs::DynamicsConstraintsSrvResponse::ConstPtr response;
+    6282             : 
+    6283             :   {
+    6284          48 :     std::scoped_lock lock(mutex_tracker_list_);
+    6285             : 
+    6286             :     // for each tracker
+    6287         168 :     for (int i = 0; i < int(tracker_list_.size()); i++) {
+    6288             : 
+    6289             :       // if it is the active one, update and retrieve the command
+    6290         432 :       response = tracker_list_[i]->setConstraints(
+    6291         432 :           mrs_msgs::DynamicsConstraintsSrvRequest::ConstPtr(std::make_unique<mrs_msgs::DynamicsConstraintsSrvRequest>(constraints)));
+    6292             :     }
+    6293             :   }
+    6294          24 : }
+    6295             : 
+    6296             : //}
+    6297             : 
+    6298             : /* setConstraintsToControllers() //{ */
+    6299             : 
+    6300          32 : void ControlManager::setConstraintsToControllers(const mrs_msgs::DynamicsConstraintsSrvRequest& constraints) {
+    6301             : 
+    6302          96 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("setConstraintsToControllers");
+    6303          96 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::setConstraintsToControllers", scope_timer_logger_, scope_timer_enabled_);
+    6304             : 
+    6305          32 :   mrs_msgs::DynamicsConstraintsSrvResponse::ConstPtr response;
+    6306             : 
+    6307             :   {
+    6308          64 :     std::scoped_lock lock(mutex_controller_list_);
+    6309             : 
+    6310             :     // for each controller
+    6311         192 :     for (int i = 0; i < int(controller_list_.size()); i++) {
+    6312             : 
+    6313             :       // if it is the active one, update and retrieve the command
+    6314         480 :       response = controller_list_[i]->setConstraints(
+    6315         480 :           mrs_msgs::DynamicsConstraintsSrvRequest::ConstPtr(std::make_unique<mrs_msgs::DynamicsConstraintsSrvRequest>(constraints)));
+    6316             :     }
+    6317             :   }
+    6318          32 : }
+    6319             : 
+    6320             : //}
+    6321             : 
+    6322             : /* setConstraints() //{ */
+    6323             : 
+    6324           7 : void ControlManager::setConstraints(const mrs_msgs::DynamicsConstraintsSrvRequest& constraints) {
+    6325             : 
+    6326          21 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("setConstraints");
+    6327          21 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::setConstraints", scope_timer_logger_, scope_timer_enabled_);
+    6328             : 
+    6329           7 :   mrs_msgs::DynamicsConstraintsSrvResponse::ConstPtr response;
+    6330             : 
+    6331           7 :   setConstraintsToTrackers(constraints);
+    6332             : 
+    6333           7 :   setConstraintsToControllers(constraints);
+    6334           7 : }
+    6335             : 
+    6336             : //}
+    6337             : 
+    6338             : 
+    6339             : /* enforceControllerConstraints() //{ */
+    6340             : 
+    6341        6810 : std::optional<mrs_msgs::DynamicsConstraintsSrvRequest> ControlManager::enforceControllersConstraints(
+    6342             :     const mrs_msgs::DynamicsConstraintsSrvRequest& constraints) {
+    6343             : 
+    6344             :   // copy member variables
+    6345       13620 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    6346             : 
+    6347        6810 :   if (!last_control_output.control_output || !last_control_output.diagnostics.controller_enforcing_constraints) {
+    6348        3535 :     return {};
+    6349             :   }
+    6350             : 
+    6351        3275 :   bool enforcing = false;
+    6352             : 
+    6353        3275 :   auto constraints_out = constraints;
+    6354             : 
+    6355        6550 :   std::scoped_lock lock(mutex_tracker_list_);
+    6356             : 
+    6357             :   // enforce horizontal speed
+    6358        3275 :   if (last_control_output.diagnostics.horizontal_speed_constraint < constraints.constraints.horizontal_speed) {
+    6359        1066 :     constraints_out.constraints.horizontal_speed = last_control_output.diagnostics.horizontal_speed_constraint;
+    6360             : 
+    6361        1066 :     enforcing = true;
+    6362             :   }
+    6363             : 
+    6364             :   // enforce horizontal acceleration
+    6365        3275 :   if (last_control_output.diagnostics.horizontal_acc_constraint < constraints.constraints.horizontal_acceleration) {
+    6366        1807 :     constraints_out.constraints.horizontal_acceleration = last_control_output.diagnostics.horizontal_acc_constraint;
+    6367             : 
+    6368        1807 :     enforcing = true;
+    6369             :   }
+    6370             : 
+    6371             :   // enforce vertical ascending speed
+    6372        3275 :   if (last_control_output.diagnostics.vertical_asc_speed_constraint < constraints.constraints.vertical_ascending_speed) {
+    6373        1066 :     constraints_out.constraints.vertical_ascending_speed = last_control_output.diagnostics.vertical_asc_speed_constraint;
+    6374             : 
+    6375        1066 :     enforcing = true;
+    6376             :   }
+    6377             : 
+    6378             :   // enforce vertical ascending acceleration
+    6379        3275 :   if (last_control_output.diagnostics.vertical_asc_acc_constraint < constraints.constraints.vertical_ascending_acceleration) {
+    6380           0 :     constraints_out.constraints.vertical_ascending_acceleration = last_control_output.diagnostics.vertical_asc_acc_constraint;
+    6381             : 
+    6382           0 :     enforcing = true;
+    6383             :   }
+    6384             : 
+    6385             :   // enforce vertical descending speed
+    6386        3275 :   if (last_control_output.diagnostics.vertical_desc_speed_constraint < constraints.constraints.vertical_descending_speed) {
+    6387        1066 :     constraints_out.constraints.vertical_descending_speed = last_control_output.diagnostics.vertical_desc_speed_constraint;
+    6388             : 
+    6389        1066 :     enforcing = true;
+    6390             :   }
+    6391             : 
+    6392             :   // enforce vertical descending acceleration
+    6393        3275 :   if (last_control_output.diagnostics.vertical_desc_acc_constraint < constraints.constraints.vertical_descending_acceleration) {
+    6394           0 :     constraints_out.constraints.vertical_descending_acceleration = last_control_output.diagnostics.vertical_desc_acc_constraint;
+    6395             : 
+    6396           0 :     enforcing = true;
+    6397             :   }
+    6398             : 
+    6399        3275 :   if (enforcing) {
+    6400        1807 :     return {constraints_out};
+    6401             :   } else {
+    6402        1468 :     return {};
+    6403             :   }
+    6404             : }
+    6405             : 
+    6406             : //}
+    6407             : 
+    6408             : /* isFlyingNormally() //{ */
+    6409             : 
+    6410        1087 : bool ControlManager::isFlyingNormally(void) {
+    6411             : 
+    6412        1883 :   return (output_enabled_) && (offboard_mode_) && (armed_) &&
+    6413         784 :          (((active_tracker_idx_ != _ehover_tracker_idx_) && (active_controller_idx_ != _eland_controller_idx_) &&
+    6414         924 :            (active_controller_idx_ != _failsafe_controller_idx_)) ||
+    6415        2443 :           _controller_names_.size() == 1) &&
+    6416        1311 :          (((active_tracker_idx_ != _null_tracker_idx_) && (active_tracker_idx_ != _landoff_tracker_idx_)) || _tracker_names_.size() == 1);
+    6417             : }
+    6418             : 
+    6419             : //}
+    6420             : 
+    6421             : /* //{ getMass() */
+    6422             : 
+    6423          39 : double ControlManager::getMass(void) {
+    6424             : 
+    6425          78 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    6426             : 
+    6427          39 :   if (last_control_output.diagnostics.mass_estimator) {
+    6428           4 :     return _uav_mass_ + last_control_output.diagnostics.mass_difference;
+    6429             :   } else {
+    6430          35 :     return _uav_mass_;
+    6431             :   }
+    6432             : }
+    6433             : 
+    6434             : //}
+    6435             : 
+    6436             : /* loadConfigFile() //{ */
+    6437             : 
+    6438           0 : bool ControlManager::loadConfigFile(const std::string& file_path, const std::string ns) {
+    6439             : 
+    6440           0 :   const std::string name_space = nh_.getNamespace() + "/" + ns;
+    6441             : 
+    6442           0 :   ROS_INFO("[ControlManager]: loading '%s' under the namespace '%s'", file_path.c_str(), name_space.c_str());
+    6443             : 
+    6444             :   // load the user-requested file
+    6445             :   {
+    6446           0 :     std::string command = "rosparam load " + file_path + " " + name_space;
+    6447           0 :     int         result  = std::system(command.c_str());
+    6448             : 
+    6449           0 :     if (result != 0) {
+    6450           0 :       ROS_ERROR("[ControlManager]: failed to load '%s'", file_path.c_str());
+    6451           0 :       return false;
+    6452             :     }
+    6453             :   }
+    6454             : 
+    6455             :   // load the platform config
+    6456           0 :   if (_platform_config_ != "") {
+    6457           0 :     std::string command = "rosparam load " + _platform_config_ + " " + name_space;
+    6458           0 :     int         result  = std::system(command.c_str());
+    6459             : 
+    6460           0 :     if (result != 0) {
+    6461           0 :       ROS_ERROR("[ControlManager]: failed to load the platform config file '%s'", _platform_config_.c_str());
+    6462           0 :       return false;
+    6463             :     }
+    6464             :   }
+    6465             : 
+    6466             :   // load the custom config
+    6467           0 :   if (_custom_config_ != "") {
+    6468           0 :     std::string command = "rosparam load " + _custom_config_ + " " + name_space;
+    6469           0 :     int         result  = std::system(command.c_str());
+    6470             : 
+    6471           0 :     if (result != 0) {
+    6472           0 :       ROS_ERROR("[ControlManager]: failed to load the custom config file '%s'", _custom_config_.c_str());
+    6473           0 :       return false;
+    6474             :     }
+    6475             :   }
+    6476             : 
+    6477           0 :   return true;
+    6478             : }
+    6479             : 
+    6480             : //}
+    6481             : 
+    6482             : // | ----------------------- safety area ---------------------- |
+    6483             : 
+    6484             : /* //{ isPointInSafetyArea3d() */
+    6485             : 
+    6486           5 : bool ControlManager::isPointInSafetyArea3d(const mrs_msgs::ReferenceStamped& point) {
+    6487             : 
+    6488           5 :   if (!use_safety_area_) {
+    6489           2 :     return true;
+    6490             :   }
+    6491             : 
+    6492           6 :   auto tfed_horizontal = transformer_->transformSingle(point, _safety_area_horizontal_frame_);
+    6493             : 
+    6494           3 :   if (!tfed_horizontal) {
+    6495           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: SafetyArea: Could not transform the point to the safety area horizontal frame");
+    6496           0 :     return false;
+    6497             :   }
+    6498             : 
+    6499           3 :   if (!safety_zone_->isPointValid(tfed_horizontal->reference.position.x, tfed_horizontal->reference.position.y)) {
+    6500           0 :     return false;
+    6501             :   }
+    6502             : 
+    6503           3 :   if (point.reference.position.z < getMinZ(point.header.frame_id) || point.reference.position.z > getMaxZ(point.header.frame_id)) {
+    6504           0 :     return false;
+    6505             :   }
+    6506             : 
+    6507           3 :   return true;
+    6508             : }
+    6509             : 
+    6510             : //}
+    6511             : 
+    6512             : /* //{ isPointInSafetyArea2d() */
+    6513             : 
+    6514         666 : bool ControlManager::isPointInSafetyArea2d(const mrs_msgs::ReferenceStamped& point) {
+    6515             : 
+    6516         666 :   if (!use_safety_area_) {
+    6517           3 :     return true;
+    6518             :   }
+    6519             : 
+    6520        1326 :   auto tfed_horizontal = transformer_->transformSingle(point, _safety_area_horizontal_frame_);
+    6521             : 
+    6522         663 :   if (!tfed_horizontal) {
+    6523           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: SafetyArea: Could not transform the point to the safety area horizontal frame");
+    6524           0 :     return false;
+    6525             :   }
+    6526             : 
+    6527         663 :   if (!safety_zone_->isPointValid(tfed_horizontal->reference.position.x, tfed_horizontal->reference.position.y)) {
+    6528           0 :     return false;
+    6529             :   }
+    6530             : 
+    6531         663 :   return true;
+    6532             : }
+    6533             : 
+    6534             : //}
+    6535             : 
+    6536             : /* //{ isPathToPointInSafetyArea3d() */
+    6537             : 
+    6538           3 : bool ControlManager::isPathToPointInSafetyArea3d(const mrs_msgs::ReferenceStamped& start, const mrs_msgs::ReferenceStamped& end) {
+    6539             : 
+    6540           3 :   if (!use_safety_area_) {
+    6541           2 :     return true;
+    6542             :   }
+    6543             : 
+    6544           1 :   if (!isPointInSafetyArea3d(start) || !isPointInSafetyArea3d(end)) {
+    6545           0 :     return false;
+    6546             :   }
+    6547             : 
+    6548           2 :   mrs_msgs::ReferenceStamped start_transformed, end_transformed;
+    6549             : 
+    6550             :   {
+    6551           1 :     auto ret = transformer_->transformSingle(start, _safety_area_horizontal_frame_);
+    6552             : 
+    6553           1 :     if (!ret) {
+    6554             : 
+    6555           0 :       ROS_ERROR("[ControlManager]: SafetyArea: Could not transform the first point in the path");
+    6556             : 
+    6557           0 :       return false;
+    6558             :     }
+    6559             : 
+    6560           1 :     start_transformed = ret.value();
+    6561             :   }
+    6562             : 
+    6563             :   {
+    6564           1 :     auto ret = transformer_->transformSingle(end, _safety_area_horizontal_frame_);
+    6565             : 
+    6566           1 :     if (!ret) {
+    6567             : 
+    6568           0 :       ROS_ERROR("[ControlManager]: SafetyArea: Could not transform the first point in the path");
+    6569             : 
+    6570           0 :       return false;
+    6571             :     }
+    6572             : 
+    6573           1 :     end_transformed = ret.value();
+    6574             :   }
+    6575             : 
+    6576           1 :   return safety_zone_->isPathValid(start_transformed.reference.position.x, start_transformed.reference.position.y, end_transformed.reference.position.x,
+    6577           1 :                                    end_transformed.reference.position.y);
+    6578             : }
+    6579             : 
+    6580             : //}
+    6581             : 
+    6582             : /* //{ isPathToPointInSafetyArea2d() */
+    6583             : 
+    6584         157 : bool ControlManager::isPathToPointInSafetyArea2d(const mrs_msgs::ReferenceStamped& start, const mrs_msgs::ReferenceStamped& end) {
+    6585         157 :   if (!use_safety_area_) {
+    6586           0 :     return true;
+    6587             :   }
+    6588             : 
+    6589         314 :   mrs_msgs::ReferenceStamped start_transformed, end_transformed;
+    6590             : 
+    6591         157 :   if (!isPointInSafetyArea2d(start) || !isPointInSafetyArea2d(end)) {
+    6592           0 :     return false;
+    6593             :   }
+    6594             : 
+    6595             :   {
+    6596         157 :     auto ret = transformer_->transformSingle(start, _safety_area_horizontal_frame_);
+    6597             : 
+    6598         157 :     if (!ret) {
+    6599             : 
+    6600           0 :       ROS_ERROR("[ControlManager]: SafetyArea: Could not transform the first point in the path");
+    6601             : 
+    6602           0 :       return false;
+    6603             :     }
+    6604             : 
+    6605         157 :     start_transformed = ret.value();
+    6606             :   }
+    6607             : 
+    6608             :   {
+    6609         157 :     auto ret = transformer_->transformSingle(end, _safety_area_horizontal_frame_);
+    6610             : 
+    6611         157 :     if (!ret) {
+    6612             : 
+    6613           0 :       ROS_ERROR("[ControlManager]: SafetyArea: Could not transform the first point in the path");
+    6614             : 
+    6615           0 :       return false;
+    6616             :     }
+    6617             : 
+    6618         157 :     end_transformed = ret.value();
+    6619             :   }
+    6620             : 
+    6621         157 :   return safety_zone_->isPathValid(start_transformed.reference.position.x, start_transformed.reference.position.y, end_transformed.reference.position.x,
+    6622         157 :                                    end_transformed.reference.position.y);
+    6623             : }
+    6624             : 
+    6625             : //}
+    6626             : 
+    6627             : /* //{ getMaxZ() */
+    6628             : 
+    6629         482 : double ControlManager::getMaxZ(const std::string& frame_id) {
+    6630             : 
+    6631             :   // | ------- first, calculate max_z from the safety area ------ |
+    6632             : 
+    6633         482 :   double safety_area_max_z = std::numeric_limits<float>::max();
+    6634             : 
+    6635             :   {
+    6636             : 
+    6637         964 :     geometry_msgs::PointStamped point;
+    6638             : 
+    6639         482 :     point.header.frame_id = _safety_area_vertical_frame_;
+    6640         482 :     point.point.x         = 0;
+    6641         482 :     point.point.y         = 0;
+    6642         482 :     point.point.z         = _safety_area_max_z_;
+    6643             : 
+    6644         482 :     auto ret = transformer_->transformSingle(point, frame_id);
+    6645             : 
+    6646         482 :     if (!ret) {
+    6647           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: SafetyArea: Could not transform safety area's max_z to '%s'", frame_id.c_str());
+    6648             :     }
+    6649             : 
+    6650         482 :     safety_area_max_z = ret->point.z;
+    6651             :   }
+    6652             : 
+    6653             :   // | ------------ overwrite from estimation manager ----------- |
+    6654             : 
+    6655         482 :   double estimation_manager_max_z = std::numeric_limits<float>::max();
+    6656             : 
+    6657             :   {
+    6658             :     // if possible, override it with max z from the estimation manager
+    6659         482 :     if (sh_max_z_.hasMsg()) {
+    6660             : 
+    6661         964 :       auto msg = sh_max_z_.getMsg();
+    6662             : 
+    6663             :       // transform it into the safety area frame
+    6664         964 :       geometry_msgs::PointStamped point;
+    6665         482 :       point.header  = msg->header;
+    6666         482 :       point.point.x = 0;
+    6667         482 :       point.point.y = 0;
+    6668         482 :       point.point.z = msg->value;
+    6669             : 
+    6670         482 :       auto ret = transformer_->transformSingle(point, frame_id);
+    6671             : 
+    6672         482 :       if (!ret) {
+    6673           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: SafetyArea: Could not transform estimation manager's max_z to the current control frame");
+    6674             :       }
+    6675             : 
+    6676         482 :       estimation_manager_max_z = ret->point.z;
+    6677             :     }
+    6678             :   }
+    6679             : 
+    6680         482 :   if (estimation_manager_max_z < safety_area_max_z) {
+    6681           0 :     return estimation_manager_max_z;
+    6682             :   } else {
+    6683         482 :     return safety_area_max_z;
+    6684             :   }
+    6685             : }
+    6686             : 
+    6687             : //}
+    6688             : 
+    6689             : /* //{ getMinZ() */
+    6690             : 
+    6691        4017 : double ControlManager::getMinZ(const std::string& frame_id) {
+    6692             : 
+    6693        4017 :   if (!use_safety_area_) {
+    6694        2021 :     return std::numeric_limits<double>::lowest();
+    6695             :   }
+    6696             : 
+    6697        3992 :   geometry_msgs::PointStamped point;
+    6698             : 
+    6699        1996 :   point.header.frame_id = _safety_area_vertical_frame_;
+    6700        1996 :   point.point.x         = 0;
+    6701        1996 :   point.point.y         = 0;
+    6702        1996 :   point.point.z         = _safety_area_min_z_;
+    6703             : 
+    6704        3992 :   auto ret = transformer_->transformSingle(point, frame_id);
+    6705             : 
+    6706        1996 :   if (!ret) {
+    6707           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: SafetyArea: Could not transform safety area's min_z to '%s'", frame_id.c_str());
+    6708           0 :     return std::numeric_limits<double>::lowest();
+    6709             :   }
+    6710             : 
+    6711        1996 :   return ret->point.z;
+    6712             : }
+    6713             : 
+    6714             : //}
+    6715             : 
+    6716             : // | --------------------- obstacle bumper -------------------- |
+    6717             : 
+    6718             : /* bumperPushFromObstacle() //{ */
+    6719             : 
+    6720           0 : bool ControlManager::bumperPushFromObstacle(void) {
+    6721           0 :   if (!bumper_enabled_) {
+    6722           0 :     return true;
+    6723             :   }
+    6724             : 
+    6725           0 :   if (!sh_bumper_.hasMsg()) {
+    6726           0 :     return true;
+    6727             :   }
+    6728             : 
+    6729             :   // copy member variables
+    6730           0 :   mrs_msgs::ObstacleSectorsConstPtr bumper_data = sh_bumper_.getMsg();
+    6731           0 :   auto                              uav_state   = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    6732             : 
+    6733           0 :   double sector_size = TAU / double(bumper_data->n_horizontal_sectors);
+    6734             : 
+    6735           0 :   double direction                     = 0;
+    6736           0 :   double repulsion_distance            = std::numeric_limits<double>::max();
+    6737           0 :   bool   horizontal_collision_detected = false;
+    6738             : 
+    6739           0 :   bool vertical_collision_detected = false;
+    6740             : 
+    6741           0 :   for (int i = 0; i < int(bumper_data->n_horizontal_sectors); i++) {
+    6742             : 
+    6743           0 :     if (bumper_data->sectors[i] < 0) {
+    6744           0 :       continue;
+    6745             :     }
+    6746             : 
+    6747           0 :     bool wall_locked_horizontal = false;
+    6748             : 
+    6749             :     // if the sector is under critical distance
+    6750           0 :     if (bumper_data->sectors[i] <= _bumper_horizontal_distance_ && bumper_data->sectors[i] < repulsion_distance) {
+    6751             : 
+    6752             :       // check for locking between the oposite walls
+    6753             :       // get the desired direction of motion
+    6754           0 :       double oposite_direction  = double(i) * sector_size + M_PI;
+    6755           0 :       int    oposite_sector_idx = bumperGetSectorId(cos(oposite_direction), sin(oposite_direction), 0);
+    6756             : 
+    6757           0 :       if (bumper_data->sectors[oposite_sector_idx] > 0 &&
+    6758           0 :           ((bumper_data->sectors[i] + bumper_data->sectors[oposite_sector_idx]) <= (2 * _bumper_horizontal_distance_ + 2 * _bumper_horizontal_overshoot_))) {
+    6759             : 
+    6760           0 :         wall_locked_horizontal = true;
+    6761             : 
+    6762           0 :         if (fabs(bumper_data->sectors[i] - bumper_data->sectors[oposite_sector_idx]) <= 2 * _bumper_horizontal_overshoot_) {
+    6763             : 
+    6764           0 :           ROS_INFO_THROTTLE(1.0, "[ControlManager]: Bumper: locked between two walls");
+    6765           0 :           continue;
+    6766             :         }
+    6767             :       }
+    6768             : 
+    6769             :       // get the id of the oposite sector
+    6770           0 :       direction = oposite_direction;
+    6771             : 
+    6772             :       /* int oposite_sector_idx = (i + bumper_data->n_horizontal_sectors / 2) % bumper_data->n_horizontal_sectors; */
+    6773             : 
+    6774           0 :       ROS_WARN_THROTTLE(1.0, "[ControlManager]: Bumper: found potential collision (sector %d vs. %d), obstacle distance: %.2f, repulsing", i,
+    6775             :                         oposite_sector_idx, bumper_data->sectors[i]);
+    6776             : 
+    6777           0 :       ROS_INFO_THROTTLE(1.0, "[ControlManager]: Bumper: oposite direction: %.2f", oposite_direction);
+    6778             : 
+    6779           0 :       if (wall_locked_horizontal) {
+    6780           0 :         if (bumper_data->sectors[i] < bumper_data->sectors[oposite_sector_idx]) {
+    6781           0 :           repulsion_distance = _bumper_horizontal_overshoot_;
+    6782             :         } else {
+    6783           0 :           repulsion_distance = -_bumper_horizontal_overshoot_;
+    6784             :         }
+    6785             :       } else {
+    6786           0 :         repulsion_distance = _bumper_horizontal_distance_ + _bumper_horizontal_overshoot_ - bumper_data->sectors[i];
+    6787             :       }
+    6788             : 
+    6789           0 :       horizontal_collision_detected = true;
+    6790             :     }
+    6791             :   }
+    6792             : 
+    6793           0 :   bool   collision_above             = false;
+    6794           0 :   bool   collision_below             = false;
+    6795           0 :   double vertical_repulsion_distance = 0;
+    6796             : 
+    6797             :   // check for vertical collision down
+    6798           0 :   if (bumper_data->sectors[bumper_data->n_horizontal_sectors] > 0 && bumper_data->sectors[bumper_data->n_horizontal_sectors] <= _bumper_vertical_distance_) {
+    6799             : 
+    6800           0 :     ROS_INFO_THROTTLE(1.0, "[ControlManager]: Bumper: potential collision below");
+    6801           0 :     collision_above             = true;
+    6802           0 :     vertical_collision_detected = true;
+    6803           0 :     vertical_repulsion_distance = _bumper_vertical_distance_ - bumper_data->sectors[bumper_data->n_horizontal_sectors];
+    6804             :   }
+    6805             : 
+    6806             :   // check for vertical collision up
+    6807           0 :   if (bumper_data->sectors[bumper_data->n_horizontal_sectors + 1] > 0 &&
+    6808           0 :       bumper_data->sectors[bumper_data->n_horizontal_sectors + 1] <= _bumper_vertical_distance_) {
+    6809             : 
+    6810           0 :     ROS_INFO_THROTTLE(1.0, "[ControlManager]: Bumper: potential collision above");
+    6811           0 :     collision_below             = true;
+    6812           0 :     vertical_collision_detected = true;
+    6813           0 :     vertical_repulsion_distance = -(_bumper_vertical_distance_ - bumper_data->sectors[bumper_data->n_horizontal_sectors + 1]);
+    6814             :   }
+    6815             : 
+    6816             :   // check the up/down wall locking
+    6817           0 :   if (collision_above && collision_below) {
+    6818             : 
+    6819           0 :     if (((bumper_data->sectors[bumper_data->n_horizontal_sectors] + bumper_data->sectors[bumper_data->n_horizontal_sectors + 1]) <=
+    6820           0 :          (2 * _bumper_vertical_distance_ + 2 * _bumper_vertical_overshoot_))) {
+    6821             : 
+    6822           0 :       vertical_repulsion_distance =
+    6823           0 :           (-bumper_data->sectors[bumper_data->n_horizontal_sectors] + bumper_data->sectors[bumper_data->n_horizontal_sectors + 1]) / 2.0;
+    6824             : 
+    6825           0 :       if (fabs(bumper_data->sectors[bumper_data->n_horizontal_sectors] - bumper_data->sectors[bumper_data->n_horizontal_sectors + 1]) <=
+    6826           0 :           2 * _bumper_vertical_overshoot_) {
+    6827             : 
+    6828           0 :         ROS_INFO_THROTTLE(1.0, "[ControlManager]: Bumper: locked between the floor and ceiling");
+    6829           0 :         vertical_collision_detected = false;
+    6830             :       }
+    6831             :     }
+    6832             :   }
+    6833             : 
+    6834             :   // if potential collision was detected and we should start the repulsing_
+    6835           0 :   if (horizontal_collision_detected || vertical_collision_detected) {
+    6836             : 
+    6837           0 :     ROS_WARN_THROTTLE(1.0, "[ControlManager]: Bumper: repulsion was initiated");
+    6838             : 
+    6839           0 :     if (!repulsing_) {
+    6840             : 
+    6841           0 :       if (_bumper_switch_tracker_) {
+    6842             : 
+    6843           0 :         auto        active_tracker_idx  = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    6844           0 :         std::string active_tracker_name = _tracker_names_[active_tracker_idx];
+    6845             : 
+    6846             :         // remember the previously active tracker
+    6847           0 :         bumper_previous_tracker_ = active_tracker_name;
+    6848             : 
+    6849           0 :         if (active_tracker_name != _bumper_tracker_name_) {
+    6850             : 
+    6851           0 :           switchTracker(_bumper_tracker_name_);
+    6852             :         }
+    6853             :       }
+    6854             : 
+    6855           0 :       if (_bumper_switch_controller_) {
+    6856             : 
+    6857           0 :         auto        active_controller_idx  = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    6858           0 :         std::string active_controller_name = _controller_names_[active_controller_idx];
+    6859             : 
+    6860             :         // remember the previously active controller
+    6861           0 :         bumper_previous_controller_ = active_controller_name;
+    6862             : 
+    6863           0 :         if (active_controller_name != _bumper_controller_name_) {
+    6864             : 
+    6865           0 :           switchController(_bumper_controller_name_);
+    6866             :         }
+    6867             :       }
+    6868             :     }
+    6869             : 
+    6870           0 :     repulsing_ = true;
+    6871             : 
+    6872           0 :     mrs_msgs::BumperStatus bumper_status;
+    6873           0 :     bumper_status.repulsing = repulsing_;
+    6874             : 
+    6875           0 :     ph_bumper_status_.publish(bumper_status);
+    6876             : 
+    6877           0 :     callbacks_enabled_ = false;
+    6878             : 
+    6879           0 :     mrs_msgs::ReferenceSrvResponse::ConstPtr tracker_response;
+    6880             : 
+    6881           0 :     std_srvs::SetBoolRequest req_enable_callbacks;
+    6882             : 
+    6883             :     // create the reference in the fcu_untilted frame
+    6884           0 :     mrs_msgs::ReferenceStamped reference_fcu_untilted;
+    6885             : 
+    6886           0 :     reference_fcu_untilted.header.frame_id = "fcu_untilted";
+    6887             : 
+    6888           0 :     if (horizontal_collision_detected) {
+    6889           0 :       reference_fcu_untilted.reference.position.x = cos(direction) * repulsion_distance;
+    6890           0 :       reference_fcu_untilted.reference.position.y = sin(direction) * repulsion_distance;
+    6891             :     } else {
+    6892           0 :       reference_fcu_untilted.reference.position.x = 0;
+    6893           0 :       reference_fcu_untilted.reference.position.y = 0;
+    6894             :     }
+    6895             : 
+    6896           0 :     reference_fcu_untilted.reference.heading = 0;
+    6897             : 
+    6898           0 :     if (vertical_collision_detected) {
+    6899           0 :       reference_fcu_untilted.reference.position.z = vertical_repulsion_distance;
+    6900             :     } else {
+    6901           0 :       reference_fcu_untilted.reference.position.z = 0;
+    6902             :     }
+    6903             : 
+    6904             :     {
+    6905           0 :       std::scoped_lock lock(mutex_tracker_list_);
+    6906             : 
+    6907             :       // transform the reference into the currently used frame
+    6908             :       // this is under the mutex_tracker_list since we don't won't the odometry switch to happen
+    6909             :       // to the tracker before we actually call the goto service
+    6910             : 
+    6911           0 :       auto ret = transformer_->transformSingle(reference_fcu_untilted, uav_state.header.frame_id);
+    6912             : 
+    6913           0 :       if (!ret) {
+    6914             : 
+    6915           0 :         ROS_WARN_THROTTLE(1.0, "[ControlManager]: Bumper: bumper reference could not be transformed");
+    6916           0 :         return false;
+    6917             :       }
+    6918             : 
+    6919           0 :       reference_fcu_untilted = ret.value();
+    6920             : 
+    6921             :       // copy the reference into the service type message
+    6922           0 :       mrs_msgs::ReferenceSrvRequest req_goto_out;
+    6923           0 :       req_goto_out.reference = reference_fcu_untilted.reference;
+    6924             : 
+    6925             :       // disable callbacks of all trackers
+    6926           0 :       req_enable_callbacks.data = false;
+    6927           0 :       for (int i = 0; i < int(tracker_list_.size()); i++) {
+    6928           0 :         tracker_list_[i]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    6929             :       }
+    6930             : 
+    6931             :       // enable the callbacks for the active tracker
+    6932           0 :       req_enable_callbacks.data = true;
+    6933           0 :       tracker_list_[active_tracker_idx_]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    6934             : 
+    6935             :       // call the goto
+    6936           0 :       tracker_response = tracker_list_[active_tracker_idx_]->setReference(
+    6937           0 :           mrs_msgs::ReferenceSrvRequest::ConstPtr(std::make_unique<mrs_msgs::ReferenceSrvRequest>(req_goto_out)));
+    6938             : 
+    6939             :       // disable the callbacks back again
+    6940           0 :       req_enable_callbacks.data = false;
+    6941           0 :       tracker_list_[active_tracker_idx_]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    6942             :     }
+    6943             :   }
+    6944             : 
+    6945             :   // if repulsing_ and the distance is safe once again
+    6946           0 :   if ((repulsing_ && !horizontal_collision_detected && !vertical_collision_detected)) {
+    6947             : 
+    6948           0 :     ROS_INFO_THROTTLE(1.0, "[ControlManager]: Bumper: repulsion was stopped");
+    6949             : 
+    6950           0 :     if (_bumper_switch_tracker_) {
+    6951             : 
+    6952           0 :       auto        active_tracker_idx  = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    6953           0 :       std::string active_tracker_name = _tracker_names_[active_tracker_idx];
+    6954             : 
+    6955           0 :       if (active_tracker_name != bumper_previous_tracker_) {
+    6956             : 
+    6957           0 :         switchTracker(bumper_previous_tracker_);
+    6958             :       }
+    6959             :     }
+    6960             : 
+    6961           0 :     if (_bumper_switch_controller_) {
+    6962             : 
+    6963           0 :       auto        active_controller_idx  = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    6964           0 :       std::string active_controller_name = _controller_names_[active_controller_idx];
+    6965             : 
+    6966           0 :       if (active_controller_name != bumper_previous_controller_) {
+    6967             : 
+    6968           0 :         switchController(bumper_previous_controller_);
+    6969             :       }
+    6970             :     }
+    6971             : 
+    6972           0 :     std_srvs::SetBoolRequest req_enable_callbacks;
+    6973             : 
+    6974             :     {
+    6975           0 :       std::scoped_lock lock(mutex_tracker_list_);
+    6976             : 
+    6977             :       // enable callbacks of all trackers
+    6978           0 :       req_enable_callbacks.data = true;
+    6979           0 :       for (int i = 0; i < int(tracker_list_.size()); i++) {
+    6980           0 :         tracker_list_[i]->enableCallbacks(std_srvs::SetBoolRequest::ConstPtr(std::make_unique<std_srvs::SetBoolRequest>(req_enable_callbacks)));
+    6981             :       }
+    6982             :     }
+    6983             : 
+    6984           0 :     callbacks_enabled_ = true;
+    6985             : 
+    6986           0 :     repulsing_ = false;
+    6987             :   }
+    6988             : 
+    6989           0 :   return false;
+    6990             : }
+    6991             : 
+    6992             : //}
+    6993             : 
+    6994             : /* bumperGetSectorId() //{ */
+    6995             : 
+    6996           0 : int ControlManager::bumperGetSectorId(const double& x, const double& y, [[maybe_unused]] const double& z) {
+    6997             :   // copy member variables
+    6998           0 :   mrs_msgs::ObstacleSectorsConstPtr bumper_data = sh_bumper_.getMsg();
+    6999             : 
+    7000             :   // heading of the point in drone frame
+    7001           0 :   double point_heading_horizontal = atan2(y, x);
+    7002             : 
+    7003           0 :   point_heading_horizontal += TAU;
+    7004             : 
+    7005             :   // if point_heading_horizontal is greater then 2*M_PI mod it
+    7006           0 :   if (fabs(point_heading_horizontal) >= TAU) {
+    7007           0 :     point_heading_horizontal = fmod(point_heading_horizontal, TAU);
+    7008             :   }
+    7009             : 
+    7010             :   // heading of the right edge of the first sector
+    7011           0 :   double sector_size = TAU / double(bumper_data->n_horizontal_sectors);
+    7012             : 
+    7013             :   // calculate the idx
+    7014           0 :   int idx = floor((point_heading_horizontal + (sector_size / 2.0)) / sector_size);
+    7015             : 
+    7016           0 :   if (idx > int(bumper_data->n_horizontal_sectors) - 1) {
+    7017           0 :     idx -= bumper_data->n_horizontal_sectors;
+    7018             :   }
+    7019             : 
+    7020           0 :   return idx;
+    7021             : }
+    7022             : 
+    7023             : //}
+    7024             : 
+    7025             : // | ------------------------- safety ------------------------- |
+    7026             : 
+    7027             : /* //{ changeLandingState() */
+    7028             : 
+    7029           6 : void ControlManager::changeLandingState(LandingStates_t new_state) {
+    7030             :   // copy member variables
+    7031          12 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    7032             : 
+    7033             :   {
+    7034           6 :     std::scoped_lock lock(mutex_landing_state_machine_);
+    7035             : 
+    7036           6 :     previous_state_landing_ = current_state_landing_;
+    7037           6 :     current_state_landing_  = new_state;
+    7038             :   }
+    7039             : 
+    7040           6 :   switch (current_state_landing_) {
+    7041             : 
+    7042           3 :     case IDLE_STATE:
+    7043           3 :       break;
+    7044           3 :     case LANDING_STATE: {
+    7045             : 
+    7046           3 :       ROS_DEBUG("[ControlManager]: starting eland timer");
+    7047           3 :       timer_eland_.start();
+    7048           3 :       ROS_DEBUG("[ControlManager]: eland timer started");
+    7049           3 :       eland_triggered_ = true;
+    7050           3 :       bumper_enabled_  = false;
+    7051             : 
+    7052           3 :       landing_uav_mass_ = getMass();
+    7053             :     }
+    7054             : 
+    7055           3 :     break;
+    7056             :   }
+    7057             : 
+    7058           6 :   ROS_INFO("[ControlManager]: switching emergency landing state %s -> %s", state_names[previous_state_landing_], state_names[current_state_landing_]);
+    7059           6 : }
+    7060             : 
+    7061             : //}
+    7062             : 
+    7063             : /* hover() //{ */
+    7064             : 
+    7065           0 : std::tuple<bool, std::string> ControlManager::hover(void) {
+    7066           0 :   if (!is_initialized_)
+    7067           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7068             : 
+    7069           0 :   if (eland_triggered_)
+    7070           0 :     return std::tuple(false, "cannot hover, eland already triggered");
+    7071             : 
+    7072           0 :   if (failsafe_triggered_)
+    7073           0 :     return std::tuple(false, "cannot hover, failsafe already triggered");
+    7074             : 
+    7075             :   {
+    7076           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    7077             : 
+    7078           0 :     std_srvs::TriggerResponse::ConstPtr response;
+    7079           0 :     std_srvs::TriggerRequest            request;
+    7080             : 
+    7081           0 :     response = tracker_list_[active_tracker_idx_]->hover(std_srvs::TriggerRequest::ConstPtr(std::make_unique<std_srvs::TriggerRequest>(request)));
+    7082             : 
+    7083           0 :     if (response != std_srvs::TriggerResponse::Ptr()) {
+    7084             : 
+    7085           0 :       return std::tuple(response->success, response->message);
+    7086             : 
+    7087             :     } else {
+    7088             : 
+    7089           0 :       std::stringstream ss;
+    7090           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'hover()' function!";
+    7091             : 
+    7092           0 :       return std::tuple(false, ss.str());
+    7093             :     }
+    7094             :   }
+    7095             : }
+    7096             : 
+    7097             : //}
+    7098             : 
+    7099             : /* //{ ehover() */
+    7100             : 
+    7101           0 : std::tuple<bool, std::string> ControlManager::ehover(void) {
+    7102           0 :   if (!is_initialized_)
+    7103           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7104             : 
+    7105           0 :   if (eland_triggered_)
+    7106           0 :     return std::tuple(false, "cannot ehover, eland already triggered");
+    7107             : 
+    7108           0 :   if (failsafe_triggered_)
+    7109           0 :     return std::tuple(false, "cannot ehover, failsafe already triggered");
+    7110             : 
+    7111             :   // copy the member variables
+    7112           0 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    7113           0 :   auto last_tracker_cmd    = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    7114           0 :   auto active_tracker_idx  = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    7115             : 
+    7116           0 :   if (active_tracker_idx == _null_tracker_idx_) {
+    7117             : 
+    7118           0 :     std::stringstream ss;
+    7119           0 :     ss << "can not trigger ehover while not flying";
+    7120           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7121             : 
+    7122           0 :     return std::tuple(false, ss.str());
+    7123             :   }
+    7124             : 
+    7125           0 :   ungripSrv();
+    7126             : 
+    7127             :   {
+    7128             : 
+    7129           0 :     auto [success, message] = switchTracker(_ehover_tracker_name_);
+    7130             : 
+    7131             :     // check if the tracker was successfully switched
+    7132             :     // this is vital, that is the core of the hover
+    7133           0 :     if (!success) {
+    7134             : 
+    7135           0 :       std::stringstream ss;
+    7136           0 :       ss << "error during switching to ehover tracker: '" << message << "'";
+    7137           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7138             : 
+    7139           0 :       return std::tuple(success, ss.str());
+    7140             :     }
+    7141             :   }
+    7142             : 
+    7143             :   {
+    7144           0 :     auto [success, message] = switchController(_eland_controller_name_);
+    7145             : 
+    7146             :     // check if the controller was successfully switched
+    7147             :     // this is not vital, we can continue without that
+    7148           0 :     if (!success) {
+    7149             : 
+    7150           0 :       std::stringstream ss;
+    7151           0 :       ss << "error during switching to ehover controller: '" << message << "'";
+    7152           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7153             :     }
+    7154             :   }
+    7155             : 
+    7156           0 :   std::stringstream ss;
+    7157           0 :   ss << "ehover activated";
+    7158           0 :   ROS_INFO_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7159             : 
+    7160           0 :   callbacks_enabled_ = false;
+    7161             : 
+    7162           0 :   return std::tuple(true, ss.str());
+    7163             : }
+    7164             : 
+    7165             : //}
+    7166             : 
+    7167             : /* eland() //{ */
+    7168             : 
+    7169           3 : std::tuple<bool, std::string> ControlManager::eland(void) {
+    7170           3 :   if (!is_initialized_)
+    7171           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7172             : 
+    7173           3 :   if (eland_triggered_)
+    7174           0 :     return std::tuple(false, "cannot eland, eland already triggered");
+    7175             : 
+    7176           3 :   if (failsafe_triggered_)
+    7177           0 :     return std::tuple(false, "cannot eland, failsafe already triggered");
+    7178             : 
+    7179             :   // copy member variables
+    7180           6 :   auto last_tracker_cmd    = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    7181           6 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    7182           3 :   auto active_tracker_idx  = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    7183             : 
+    7184           3 :   if (active_tracker_idx == _null_tracker_idx_) {
+    7185             : 
+    7186           0 :     std::stringstream ss;
+    7187           0 :     ss << "can not trigger eland while not flying";
+    7188           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7189             : 
+    7190           0 :     return std::tuple(false, ss.str());
+    7191             :   }
+    7192             : 
+    7193           3 :   if (_rc_emergency_handoff_) {
+    7194             : 
+    7195           0 :     toggleOutput(false);
+    7196             : 
+    7197           0 :     return std::tuple(true, "RC emergency handoff is ON, disabling output");
+    7198             :   }
+    7199             : 
+    7200             :   {
+    7201           3 :     auto [success, message] = switchTracker(_ehover_tracker_name_);
+    7202             : 
+    7203             :     // check if the tracker was successfully switched
+    7204             :     // this is vital
+    7205           3 :     if (!success) {
+    7206             : 
+    7207           0 :       std::stringstream ss;
+    7208           0 :       ss << "error during switching to eland tracker: '" << message << "'";
+    7209           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7210             : 
+    7211           0 :       return std::tuple(success, ss.str());
+    7212             :     }
+    7213             :   }
+    7214             : 
+    7215             :   {
+    7216           6 :     auto [success, message] = switchController(_eland_controller_name_);
+    7217             : 
+    7218             :     // check if the controller was successfully switched
+    7219             :     // this is not vital, we can continue without it
+    7220           3 :     if (!success) {
+    7221             : 
+    7222           0 :       std::stringstream ss;
+    7223           0 :       ss << "error during switching to eland controller: '" << message << "'";
+    7224           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7225             :     }
+    7226             :   }
+    7227             : 
+    7228             :   // | ----------------- call the eland service ----------------- |
+    7229             : 
+    7230           3 :   std::stringstream ss;
+    7231             :   bool              success;
+    7232             : 
+    7233           3 :   if (elandSrv()) {
+    7234             : 
+    7235           3 :     changeLandingState(LANDING_STATE);
+    7236             : 
+    7237           3 :     odometryCallbacksSrv(false);
+    7238             : 
+    7239           3 :     ss << "eland activated";
+    7240           3 :     ROS_INFO_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7241             : 
+    7242           3 :     success = true;
+    7243             : 
+    7244           3 :     callbacks_enabled_ = false;
+    7245             : 
+    7246             :   } else {
+    7247             : 
+    7248           0 :     ss << "error during activation of eland";
+    7249           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7250             : 
+    7251           0 :     success = false;
+    7252             :   }
+    7253             : 
+    7254           6 :   return std::tuple(success, ss.str());
+    7255             : }
+    7256             : 
+    7257             : //}
+    7258             : 
+    7259             : /* failsafe() //{ */
+    7260             : 
+    7261           1 : std::tuple<bool, std::string> ControlManager::failsafe(void) {
+    7262             :   // copy member variables
+    7263           2 :   auto last_control_output   = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    7264           2 :   auto last_tracker_cmd      = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    7265           1 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    7266           1 :   auto active_tracker_idx    = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    7267             : 
+    7268           1 :   if (!is_initialized_) {
+    7269           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7270             :   }
+    7271             : 
+    7272           1 :   if (failsafe_triggered_) {
+    7273           0 :     return std::tuple(false, "cannot, failsafe already triggered");
+    7274             :   }
+    7275             : 
+    7276           1 :   if (active_tracker_idx == _null_tracker_idx_) {
+    7277             : 
+    7278           0 :     std::stringstream ss;
+    7279           0 :     ss << "can not trigger failsafe while not flying";
+    7280           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7281           0 :     return std::tuple(false, ss.str());
+    7282             :   }
+    7283             : 
+    7284           1 :   if (_rc_emergency_handoff_) {
+    7285             : 
+    7286           0 :     toggleOutput(false);
+    7287             : 
+    7288           0 :     return std::tuple(true, "RC emergency handoff is ON, disabling output");
+    7289             :   }
+    7290             : 
+    7291           1 :   if (_parachute_enabled_) {
+    7292             : 
+    7293           0 :     auto [success, message] = deployParachute();
+    7294             : 
+    7295           0 :     if (success) {
+    7296             : 
+    7297           0 :       std::stringstream ss;
+    7298           0 :       ss << "failsafe activated (parachute): '" << message << "'";
+    7299           0 :       ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    7300             : 
+    7301           0 :       return std::tuple(true, ss.str());
+    7302             : 
+    7303             :     } else {
+    7304             : 
+    7305           0 :       std::stringstream ss;
+    7306           0 :       ss << "could not deploy parachute: '" << message << "', continuing with normal failsafe";
+    7307           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7308             :     }
+    7309             :   }
+    7310             : 
+    7311           1 :   if (_failsafe_controller_idx_ != active_controller_idx) {
+    7312             : 
+    7313             :     try {
+    7314             : 
+    7315           2 :       std::scoped_lock lock(mutex_controller_list_);
+    7316             : 
+    7317           1 :       ROS_INFO("[ControlManager]: activating the controller '%s'", _failsafe_controller_name_.c_str());
+    7318           1 :       controller_list_[_failsafe_controller_idx_]->activate(last_control_output);
+    7319             : 
+    7320             :       {
+    7321           2 :         std::scoped_lock lock(mutex_controller_tracker_switch_time_);
+    7322             : 
+    7323             :         // update the time (used in failsafe)
+    7324           1 :         controller_tracker_switch_time_ = ros::Time::now();
+    7325             :       }
+    7326             : 
+    7327           1 :       failsafe_triggered_ = true;
+    7328           1 :       ROS_DEBUG("[ControlManager]: stopping eland timer");
+    7329           1 :       timer_eland_.stop();
+    7330           1 :       ROS_DEBUG("[ControlManager]: eland timer stopped");
+    7331             : 
+    7332           1 :       landing_uav_mass_ = getMass();
+    7333             : 
+    7334           1 :       eland_triggered_ = false;
+    7335           1 :       ROS_DEBUG("[ControlManager]: starting failsafe timer");
+    7336           1 :       timer_failsafe_.start();
+    7337           1 :       ROS_DEBUG("[ControlManager]: failsafe timer started");
+    7338             : 
+    7339           1 :       bumper_enabled_ = false;
+    7340             : 
+    7341           1 :       odometryCallbacksSrv(false);
+    7342             : 
+    7343           1 :       callbacks_enabled_ = false;
+    7344             : 
+    7345           1 :       ROS_INFO_THROTTLE(1.0, "[ControlManager]: the controller '%s' was activated", _failsafe_controller_name_.c_str());
+    7346             : 
+    7347             :       // super important, switch the active controller idx
+    7348             :       try {
+    7349           1 :         controller_list_[active_controller_idx_]->deactivate();
+    7350           1 :         active_controller_idx_ = _failsafe_controller_idx_;
+    7351             :       }
+    7352           0 :       catch (std::runtime_error& exrun) {
+    7353           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: could not deactivate the controller '%s'", _controller_names_[active_controller_idx_].c_str());
+    7354             :       }
+    7355             :     }
+    7356           0 :     catch (std::runtime_error& exrun) {
+    7357           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: error during activation of the controller '%s'", _failsafe_controller_name_.c_str());
+    7358           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception: '%s'", exrun.what());
+    7359             :     }
+    7360             :   }
+    7361             : 
+    7362           2 :   return std::tuple(true, "failsafe activated");
+    7363             : }
+    7364             : 
+    7365             : //}
+    7366             : 
+    7367             : /* escalatingFailsafe() //{ */
+    7368             : 
+    7369           0 : std::tuple<bool, std::string> ControlManager::escalatingFailsafe(void) {
+    7370           0 :   std::stringstream ss;
+    7371             : 
+    7372           0 :   if ((ros::Time::now() - escalating_failsafe_time_).toSec() < _escalating_failsafe_timeout_) {
+    7373             : 
+    7374           0 :     ss << "too soon for escalating failsafe";
+    7375           0 :     ROS_WARN_STREAM_THROTTLE(0.1, "[ControlManager]: " << ss.str());
+    7376             : 
+    7377           0 :     return std::tuple(false, ss.str());
+    7378             :   }
+    7379             : 
+    7380           0 :   if (!output_enabled_) {
+    7381             : 
+    7382           0 :     ss << "not escalating failsafe, output is disabled";
+    7383           0 :     ROS_WARN_STREAM_THROTTLE(0.1, "[ControlManager]: " << ss.str());
+    7384             : 
+    7385           0 :     return std::tuple(false, ss.str());
+    7386             :   }
+    7387             : 
+    7388           0 :   ROS_WARN("[ControlManager]: escalating failsafe triggered");
+    7389             : 
+    7390           0 :   auto active_tracker_idx    = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    7391           0 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    7392             : 
+    7393           0 :   std::string active_tracker_name    = _tracker_names_[active_tracker_idx];
+    7394           0 :   std::string active_controller_name = _controller_names_[active_controller_idx];
+    7395             : 
+    7396           0 :   EscalatingFailsafeStates_t next_state = getNextEscFailsafeState();
+    7397             : 
+    7398           0 :   escalating_failsafe_time_ = ros::Time::now();
+    7399             : 
+    7400           0 :   switch (next_state) {
+    7401             : 
+    7402           0 :     case ESC_NONE_STATE: {
+    7403             : 
+    7404           0 :       ss << "escalating failsafe has run to impossible situation";
+    7405           0 :       ROS_ERROR_STREAM_THROTTLE(0.1, "[ControlManager]: " << ss.str());
+    7406             : 
+    7407           0 :       return std::tuple(false, "escalating failsafe has run to impossible situation");
+    7408             : 
+    7409             :       break;
+    7410             :     }
+    7411             : 
+    7412           0 :     case ESC_EHOVER_STATE: {
+    7413             : 
+    7414           0 :       ss << "escalating failsafe escalates to ehover";
+    7415           0 :       ROS_WARN_STREAM_THROTTLE(0.1, "[ControlManager]: " << ss.str());
+    7416             : 
+    7417           0 :       auto [success, message] = ehover();
+    7418             : 
+    7419           0 :       if (success) {
+    7420           0 :         state_escalating_failsafe_ = ESC_EHOVER_STATE;
+    7421             :       }
+    7422             : 
+    7423           0 :       return {success, message};
+    7424             : 
+    7425             :       break;
+    7426             :     }
+    7427             : 
+    7428           0 :     case ESC_ELAND_STATE: {
+    7429             : 
+    7430           0 :       ss << "escalating failsafe escalates to eland";
+    7431           0 :       ROS_WARN_STREAM_THROTTLE(0.1, "[ControlManager]: " << ss.str());
+    7432             : 
+    7433           0 :       auto [success, message] = eland();
+    7434             : 
+    7435           0 :       if (success) {
+    7436           0 :         state_escalating_failsafe_ = ESC_ELAND_STATE;
+    7437             :       }
+    7438             : 
+    7439           0 :       return {success, message};
+    7440             : 
+    7441             :       break;
+    7442             :     }
+    7443             : 
+    7444           0 :     case ESC_FAILSAFE_STATE: {
+    7445             : 
+    7446           0 :       escalating_failsafe_time_ = ros::Time::now();
+    7447             : 
+    7448           0 :       ss << "escalating failsafe escalates to failsafe";
+    7449           0 :       ROS_WARN_STREAM_THROTTLE(0.1, "[ControlManager]: " << ss.str());
+    7450             : 
+    7451           0 :       auto [success, message] = failsafe();
+    7452             : 
+    7453           0 :       if (success) {
+    7454           0 :         state_escalating_failsafe_ = ESC_FINISHED_STATE;
+    7455             :       }
+    7456             : 
+    7457           0 :       return {success, message};
+    7458             : 
+    7459             :       break;
+    7460             :     }
+    7461             : 
+    7462           0 :     case ESC_FINISHED_STATE: {
+    7463             : 
+    7464           0 :       escalating_failsafe_time_ = ros::Time::now();
+    7465             : 
+    7466           0 :       ss << "escalating failsafe has nothing more to do";
+    7467           0 :       ROS_WARN_STREAM_THROTTLE(0.1, "[ControlManager]: " << ss.str());
+    7468             : 
+    7469           0 :       return std::tuple(false, "escalating failsafe has nothing more to do");
+    7470             : 
+    7471             :       break;
+    7472             :     }
+    7473             : 
+    7474           0 :     default: {
+    7475             : 
+    7476           0 :       break;
+    7477             :     }
+    7478             :   }
+    7479             : 
+    7480           0 :   ROS_ERROR("[ControlManager]: escalatingFailsafe() reached the final return, this should not happen!");
+    7481             : 
+    7482           0 :   return std::tuple(false, "escalating failsafe exception");
+    7483             : }
+    7484             : 
+    7485             : //}
+    7486             : 
+    7487             : /* getNextEscFailsafeState() //{ */
+    7488             : 
+    7489           0 : EscalatingFailsafeStates_t ControlManager::getNextEscFailsafeState(void) {
+    7490           0 :   EscalatingFailsafeStates_t current_state = state_escalating_failsafe_;
+    7491             : 
+    7492           0 :   switch (current_state) {
+    7493             : 
+    7494           0 :     case ESC_FINISHED_STATE: {
+    7495             : 
+    7496           0 :       return ESC_FINISHED_STATE;
+    7497             : 
+    7498             :       break;
+    7499             :     }
+    7500             : 
+    7501           0 :     case ESC_NONE_STATE: {
+    7502             : 
+    7503           0 :       if (_escalating_failsafe_ehover_) {
+    7504           0 :         return ESC_EHOVER_STATE;
+    7505           0 :       } else if (_escalating_failsafe_eland_) {
+    7506           0 :         return ESC_ELAND_STATE;
+    7507           0 :       } else if (_escalating_failsafe_failsafe_) {
+    7508           0 :         return ESC_FAILSAFE_STATE;
+    7509             :       } else {
+    7510           0 :         return ESC_FINISHED_STATE;
+    7511             :       }
+    7512             : 
+    7513             :       break;
+    7514             :     }
+    7515             : 
+    7516           0 :     case ESC_EHOVER_STATE: {
+    7517             : 
+    7518           0 :       if (_escalating_failsafe_eland_) {
+    7519           0 :         return ESC_ELAND_STATE;
+    7520           0 :       } else if (_escalating_failsafe_failsafe_) {
+    7521           0 :         return ESC_FAILSAFE_STATE;
+    7522             :       } else {
+    7523           0 :         return ESC_FINISHED_STATE;
+    7524             :       }
+    7525             : 
+    7526             :       break;
+    7527             :     }
+    7528             : 
+    7529           0 :     case ESC_ELAND_STATE: {
+    7530             : 
+    7531           0 :       if (_escalating_failsafe_failsafe_) {
+    7532           0 :         return ESC_FAILSAFE_STATE;
+    7533             :       } else {
+    7534           0 :         return ESC_FINISHED_STATE;
+    7535             :       }
+    7536             : 
+    7537             :       break;
+    7538             :     }
+    7539             : 
+    7540           0 :     case ESC_FAILSAFE_STATE: {
+    7541             : 
+    7542           0 :       return ESC_FINISHED_STATE;
+    7543             : 
+    7544             :       break;
+    7545             :     }
+    7546             :   }
+    7547             : 
+    7548           0 :   ROS_ERROR("[ControlManager]: getNextEscFailsafeState() reached the final return, this should not happen!");
+    7549             : 
+    7550           0 :   return ESC_NONE_STATE;
+    7551             : }
+    7552             : 
+    7553             : //}
+    7554             : 
+    7555             : // | ------------------- trajectory tracking ------------------ |
+    7556             : 
+    7557             : /* startTrajectoryTracking() //{ */
+    7558             : 
+    7559           0 : std::tuple<bool, std::string> ControlManager::startTrajectoryTracking(void) {
+    7560           0 :   if (!is_initialized_)
+    7561           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7562             : 
+    7563             :   {
+    7564           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    7565             : 
+    7566           0 :     std_srvs::TriggerResponse::ConstPtr response;
+    7567           0 :     std_srvs::TriggerRequest            request;
+    7568             : 
+    7569             :     response =
+    7570           0 :         tracker_list_[active_tracker_idx_]->startTrajectoryTracking(std_srvs::TriggerRequest::ConstPtr(std::make_unique<std_srvs::TriggerRequest>(request)));
+    7571             : 
+    7572           0 :     if (response != std_srvs::TriggerResponse::Ptr()) {
+    7573             : 
+    7574           0 :       return std::tuple(response->success, response->message);
+    7575             : 
+    7576             :     } else {
+    7577             : 
+    7578           0 :       std::stringstream ss;
+    7579           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'startTrajectoryTracking()' function!";
+    7580             : 
+    7581           0 :       return std::tuple(false, ss.str());
+    7582             :     }
+    7583             :   }
+    7584             : }
+    7585             : 
+    7586             : //}
+    7587             : 
+    7588             : /* stopTrajectoryTracking() //{ */
+    7589             : 
+    7590           0 : std::tuple<bool, std::string> ControlManager::stopTrajectoryTracking(void) {
+    7591           0 :   if (!is_initialized_)
+    7592           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7593             : 
+    7594             :   {
+    7595           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    7596             : 
+    7597           0 :     std_srvs::TriggerResponse::ConstPtr response;
+    7598           0 :     std_srvs::TriggerRequest            request;
+    7599             : 
+    7600             :     response =
+    7601           0 :         tracker_list_[active_tracker_idx_]->stopTrajectoryTracking(std_srvs::TriggerRequest::ConstPtr(std::make_unique<std_srvs::TriggerRequest>(request)));
+    7602             : 
+    7603           0 :     if (response != std_srvs::TriggerResponse::Ptr()) {
+    7604             : 
+    7605           0 :       return std::tuple(response->success, response->message);
+    7606             : 
+    7607             :     } else {
+    7608             : 
+    7609           0 :       std::stringstream ss;
+    7610           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'stopTrajectoryTracking()' function!";
+    7611             : 
+    7612           0 :       return std::tuple(false, ss.str());
+    7613             :     }
+    7614             :   }
+    7615             : }
+    7616             : 
+    7617             : //}
+    7618             : 
+    7619             : /* resumeTrajectoryTracking() //{ */
+    7620             : 
+    7621           0 : std::tuple<bool, std::string> ControlManager::resumeTrajectoryTracking(void) {
+    7622           0 :   if (!is_initialized_)
+    7623           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7624             : 
+    7625             :   {
+    7626           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    7627             : 
+    7628           0 :     std_srvs::TriggerResponse::ConstPtr response;
+    7629           0 :     std_srvs::TriggerRequest            request;
+    7630             : 
+    7631             :     response =
+    7632           0 :         tracker_list_[active_tracker_idx_]->resumeTrajectoryTracking(std_srvs::TriggerRequest::ConstPtr(std::make_unique<std_srvs::TriggerRequest>(request)));
+    7633             : 
+    7634           0 :     if (response != std_srvs::TriggerResponse::Ptr()) {
+    7635             : 
+    7636           0 :       return std::tuple(response->success, response->message);
+    7637             : 
+    7638             :     } else {
+    7639             : 
+    7640           0 :       std::stringstream ss;
+    7641           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'resumeTrajectoryTracking()' function!";
+    7642             : 
+    7643           0 :       return std::tuple(false, ss.str());
+    7644             :     }
+    7645             :   }
+    7646             : }
+    7647             : 
+    7648             : //}
+    7649             : 
+    7650             : /* gotoTrajectoryStart() //{ */
+    7651             : 
+    7652           0 : std::tuple<bool, std::string> ControlManager::gotoTrajectoryStart(void) {
+    7653           0 :   if (!is_initialized_)
+    7654           0 :     return std::tuple(false, "the ControlManager is not initialized");
+    7655             : 
+    7656             :   {
+    7657           0 :     std::scoped_lock lock(mutex_tracker_list_);
+    7658             : 
+    7659           0 :     std_srvs::TriggerResponse::ConstPtr response;
+    7660           0 :     std_srvs::TriggerRequest            request;
+    7661             : 
+    7662           0 :     response = tracker_list_[active_tracker_idx_]->gotoTrajectoryStart(std_srvs::TriggerRequest::ConstPtr(std::make_unique<std_srvs::TriggerRequest>(request)));
+    7663             : 
+    7664           0 :     if (response != std_srvs::TriggerResponse::Ptr()) {
+    7665             : 
+    7666           0 :       return std::tuple(response->success, response->message);
+    7667             : 
+    7668             :     } else {
+    7669             : 
+    7670           0 :       std::stringstream ss;
+    7671           0 :       ss << "the tracker '" << _tracker_names_[active_tracker_idx_] << "' does not implement the 'gotoTrajectoryStart()' function!";
+    7672             : 
+    7673           0 :       return std::tuple(false, ss.str());
+    7674             :     }
+    7675             :   }
+    7676             : }
+    7677             : 
+    7678             : //}
+    7679             : 
+    7680             : // | ----------------- service client wrappers ---------------- |
+    7681             : 
+    7682             : /* arming() //{ */
+    7683             : 
+    7684           5 : std::tuple<bool, std::string> ControlManager::arming(const bool input) {
+    7685          10 :   std::stringstream ss;
+    7686             : 
+    7687           5 :   if (input) {
+    7688             : 
+    7689           0 :     ss << "not allowed to arm using the ControlManager, maybe later when we don't do bugs";
+    7690           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7691           0 :     return std::tuple(false, ss.str());
+    7692             :   }
+    7693             : 
+    7694           5 :   if (!input && !isOffboard()) {
+    7695             : 
+    7696           0 :     ss << "can not disarm, not in OFFBOARD mode";
+    7697           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7698           0 :     return std::tuple(false, ss.str());
+    7699             :   }
+    7700             : 
+    7701           5 :   if (!input && _rc_emergency_handoff_) {
+    7702             : 
+    7703           0 :     toggleOutput(false);
+    7704             : 
+    7705           0 :     return std::tuple(true, "RC emergency handoff is ON, disabling output");
+    7706             :   }
+    7707             : 
+    7708           5 :   std_srvs::SetBool srv_out;
+    7709             : 
+    7710           5 :   srv_out.request.data = input ? 1 : 0;  // arm or disarm?
+    7711             : 
+    7712           5 :   ROS_INFO("[ControlManager]: calling for %s", input ? "arming" : "disarming");
+    7713             : 
+    7714           5 :   if (sch_arming_.call(srv_out)) {
+    7715             : 
+    7716           5 :     if (srv_out.response.success) {
+    7717             : 
+    7718           5 :       ss << "service call for " << (input ? "arming" : "disarming") << " was successful";
+    7719           5 :       ROS_INFO_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7720             : 
+    7721           5 :       if (!input) {
+    7722             : 
+    7723           5 :         toggleOutput(false);
+    7724             : 
+    7725           5 :         ROS_DEBUG("[ControlManager]: stopping failsafe timer");
+    7726           5 :         timer_failsafe_.stop();
+    7727           5 :         ROS_DEBUG("[ControlManager]: failsafe timer stopped");
+    7728             : 
+    7729           5 :         ROS_DEBUG("[ControlManager]: stopping the eland timer");
+    7730           5 :         timer_eland_.stop();
+    7731           5 :         ROS_DEBUG("[ControlManager]: eland timer stopped");
+    7732             : 
+    7733           5 :         shutdown();
+    7734             :       }
+    7735             : 
+    7736             :     } else {
+    7737           0 :       ss << "service call for " << (input ? "arming" : "disarming") << " failed";
+    7738           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7739             :     }
+    7740             : 
+    7741             :   } else {
+    7742           0 :     ss << "calling for " << (input ? "arming" : "disarming") << " resulted in failure: '" << srv_out.response.message << "'";
+    7743           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[ControlManager]: " << ss.str());
+    7744             :   }
+    7745             : 
+    7746          10 :   return std::tuple(srv_out.response.success, ss.str());
+    7747             : }
+    7748             : 
+    7749             : //}
+    7750             : 
+    7751             : /* odometryCallbacksSrv() //{ */
+    7752             : 
+    7753           4 : void ControlManager::odometryCallbacksSrv(const bool input) {
+    7754           4 :   ROS_INFO("[ControlManager]: switching odometry callbacks to %s", input ? "ON" : "OFF");
+    7755             : 
+    7756           8 :   std_srvs::SetBool srv;
+    7757             : 
+    7758           4 :   srv.request.data = input;
+    7759             : 
+    7760           4 :   bool res = sch_set_odometry_callbacks_.call(srv);
+    7761             : 
+    7762           4 :   if (res) {
+    7763             : 
+    7764           4 :     if (!srv.response.success) {
+    7765           0 :       ROS_WARN("[ControlManager]: service call for toggle odometry callbacks returned: '%s'", srv.response.message.c_str());
+    7766             :     }
+    7767             : 
+    7768             :   } else {
+    7769           0 :     ROS_ERROR("[ControlManager]: service call for toggle odometry callbacks failed!");
+    7770             :   }
+    7771           4 : }
+    7772             : 
+    7773             : //}
+    7774             : 
+    7775             : /* elandSrv() //{ */
+    7776             : 
+    7777           3 : bool ControlManager::elandSrv(void) {
+    7778           3 :   ROS_INFO("[ControlManager]: calling for eland");
+    7779             : 
+    7780           6 :   std_srvs::Trigger srv;
+    7781             : 
+    7782           3 :   bool res = sch_eland_.call(srv);
+    7783             : 
+    7784           3 :   if (res) {
+    7785             : 
+    7786           3 :     if (!srv.response.success) {
+    7787           0 :       ROS_WARN("[ControlManager]: service call for eland returned: '%s'", srv.response.message.c_str());
+    7788             :     }
+    7789             : 
+    7790           3 :     return srv.response.success;
+    7791             : 
+    7792             :   } else {
+    7793             : 
+    7794           0 :     ROS_ERROR("[ControlManager]: service call for eland failed!");
+    7795             : 
+    7796           0 :     return false;
+    7797             :   }
+    7798             : }
+    7799             : 
+    7800             : //}
+    7801             : 
+    7802             : /* shutdown() //{ */
+    7803             : 
+    7804           8 : void ControlManager::shutdown() {
+    7805             :   // copy member variables
+    7806          16 :   auto uav_state = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    7807             : 
+    7808           8 :   if (_automatic_pc_shutdown_enabled_) {
+    7809             : 
+    7810           0 :     ROS_INFO("[ControlManager]: calling service for PC shutdown");
+    7811             : 
+    7812           0 :     std_srvs::Trigger shutdown_out;
+    7813           0 :     sch_shutdown_.call(shutdown_out);
+    7814             :   }
+    7815           8 : }
+    7816             : 
+    7817             : //}
+    7818             : 
+    7819             : /* parachuteSrv() //{ */
+    7820             : 
+    7821           0 : bool ControlManager::parachuteSrv(void) {
+    7822           0 :   ROS_INFO("[ControlManager]: calling for parachute deployment");
+    7823             : 
+    7824           0 :   std_srvs::Trigger srv;
+    7825             : 
+    7826           0 :   bool res = sch_parachute_.call(srv);
+    7827             : 
+    7828           0 :   if (res) {
+    7829             : 
+    7830           0 :     if (!srv.response.success) {
+    7831           0 :       ROS_WARN("[ControlManager]: service call for parachute deployment returned: '%s'", srv.response.message.c_str());
+    7832             :     }
+    7833             : 
+    7834           0 :     return srv.response.success;
+    7835             : 
+    7836             :   } else {
+    7837             : 
+    7838           0 :     ROS_ERROR("[ControlManager]: service call for parachute deployment failed!");
+    7839             : 
+    7840           0 :     return false;
+    7841             :   }
+    7842             : }
+    7843             : 
+    7844             : //}
+    7845             : 
+    7846             : /* ungripSrv() //{ */
+    7847             : 
+    7848         111 : void ControlManager::ungripSrv(void) {
+    7849         222 :   std_srvs::Trigger srv;
+    7850             : 
+    7851         111 :   bool res = sch_ungrip_.call(srv);
+    7852             : 
+    7853         111 :   if (res) {
+    7854             : 
+    7855           0 :     if (!srv.response.success) {
+    7856           0 :       ROS_DEBUG_THROTTLE(1.0, "[ControlManager]: service call for ungripping payload returned: '%s'", srv.response.message.c_str());
+    7857             :     }
+    7858             : 
+    7859             :   } else {
+    7860         111 :     ROS_DEBUG_THROTTLE(1.0, "[ControlManager]: service call for ungripping payload failed!");
+    7861             :   }
+    7862         111 : }
+    7863             : 
+    7864             : //}
+    7865             : 
+    7866             : // | ------------------------ routines ------------------------ |
+    7867             : 
+    7868             : /* toggleOutput() //{ */
+    7869             : 
+    7870          15 : void ControlManager::toggleOutput(const bool& input) {
+    7871             : 
+    7872          15 :   if (input == output_enabled_) {
+    7873           3 :     ROS_WARN_THROTTLE(0.1, "[ControlManager]: output is already %s", input ? "ON" : "OFF");
+    7874           3 :     return;
+    7875             :   }
+    7876             : 
+    7877          12 :   ROS_INFO("[ControlManager]: switching output %s", input ? "ON" : "OFF");
+    7878             : 
+    7879          12 :   output_enabled_ = input;
+    7880             : 
+    7881             :   // if switching output off, switch to NullTracker
+    7882          12 :   if (!output_enabled_) {
+    7883             : 
+    7884           5 :     ROS_INFO("[ControlManager]: switching to 'NullTracker' after switching output off");
+    7885             : 
+    7886           5 :     switchTracker(_null_tracker_name_);
+    7887             : 
+    7888           5 :     ROS_INFO_STREAM("[ControlManager]: switching to the controller '" << _eland_controller_name_ << "' after switching output off");
+    7889             : 
+    7890           5 :     switchController(_eland_controller_name_);
+    7891             : 
+    7892             :     // | --------- deactivate all trackers and controllers -------- |
+    7893             : 
+    7894          35 :     for (int i = 0; i < int(tracker_list_.size()); i++) {
+    7895             : 
+    7896          30 :       std::map<std::string, TrackerParams>::iterator it;
+    7897          30 :       it = trackers_.find(_tracker_names_[i]);
+    7898             : 
+    7899             :       try {
+    7900          30 :         ROS_INFO("[ControlManager]: deactivating the tracker '%s'", it->second.address.c_str());
+    7901          30 :         tracker_list_[i]->deactivate();
+    7902             :       }
+    7903           0 :       catch (std::runtime_error& ex) {
+    7904           0 :         ROS_ERROR("[ControlManager]: exception caught during tracker deactivation: '%s'", ex.what());
+    7905             :       }
+    7906             :     }
+    7907             : 
+    7908          30 :     for (int i = 0; i < int(controller_list_.size()); i++) {
+    7909             : 
+    7910          25 :       std::map<std::string, ControllerParams>::iterator it;
+    7911          25 :       it = controllers_.find(_controller_names_[i]);
+    7912             : 
+    7913             :       try {
+    7914          25 :         ROS_INFO("[ControlManager]: deactivating the controller '%s'", it->second.address.c_str());
+    7915          25 :         controller_list_[i]->deactivate();
+    7916             :       }
+    7917           0 :       catch (std::runtime_error& ex) {
+    7918           0 :         ROS_ERROR("[ControlManager]: exception caught during controller deactivation: '%s'", ex.what());
+    7919             :       }
+    7920             :     }
+    7921             : 
+    7922           5 :     timer_failsafe_.stop();
+    7923           5 :     timer_eland_.stop();
+    7924           5 :     timer_pirouette_.stop();
+    7925             : 
+    7926           5 :     offboard_mode_was_true_ = false;
+    7927             :   }
+    7928             : }
+    7929             : 
+    7930             : //}
+    7931             : 
+    7932             : /* switchTracker() //{ */
+    7933             : 
+    7934          24 : std::tuple<bool, std::string> ControlManager::switchTracker(const std::string& tracker_name) {
+    7935          72 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("switchTracker");
+    7936          72 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::switchTracker", scope_timer_logger_, scope_timer_enabled_);
+    7937             : 
+    7938             :   // copy member variables
+    7939          48 :   auto last_tracker_cmd   = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    7940          24 :   auto active_tracker_idx = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    7941             : 
+    7942          48 :   std::stringstream ss;
+    7943             : 
+    7944          24 :   if (!got_uav_state_) {
+    7945             : 
+    7946           0 :     ss << "can not switch tracker, missing odometry!";
+    7947           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    7948           0 :     return std::tuple(false, ss.str());
+    7949             :   }
+    7950             : 
+    7951          24 :   if (_state_input_ == INPUT_UAV_STATE && _odometry_innovation_check_enabled_ && !sh_odometry_innovation_.hasMsg()) {
+    7952             : 
+    7953           0 :     ss << "can not switch tracker, missing odometry innovation!";
+    7954           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    7955           0 :     return std::tuple(false, ss.str());
+    7956             :   }
+    7957             : 
+    7958          24 :   auto new_tracker_idx = idxInVector(tracker_name, _tracker_names_);
+    7959             : 
+    7960             :   // check if the tracker exists
+    7961          24 :   if (!new_tracker_idx) {
+    7962           0 :     ss << "the tracker '" << tracker_name << "' does not exist!";
+    7963           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    7964           0 :     return std::tuple(false, ss.str());
+    7965             :   }
+    7966             : 
+    7967             :   // check if the tracker is already active
+    7968          24 :   if (new_tracker_idx.value() == active_tracker_idx) {
+    7969           1 :     ss << "not switching, the tracker '" << tracker_name << "' is already active!";
+    7970           1 :     ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    7971           1 :     return std::tuple(true, ss.str());
+    7972             :   }
+    7973             : 
+    7974             :   {
+    7975          23 :     std::scoped_lock lock(mutex_tracker_list_);
+    7976             : 
+    7977             :     try {
+    7978             : 
+    7979          23 :       ROS_INFO("[ControlManager]: activating the tracker '%s'", _tracker_names_[new_tracker_idx.value()].c_str());
+    7980             : 
+    7981          23 :       auto [success, message] = tracker_list_[new_tracker_idx.value()]->activate(last_tracker_cmd);
+    7982             : 
+    7983          23 :       if (!success) {
+    7984             : 
+    7985           0 :         ss << "the tracker '" << tracker_name << "' could not be activated: '" << message << "'";
+    7986           0 :         ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    7987           0 :         return std::tuple(false, ss.str());
+    7988             : 
+    7989             :       } else {
+    7990             : 
+    7991          23 :         ss << "the tracker '" << tracker_name << "' was activated";
+    7992          23 :         ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    7993             : 
+    7994             :         {
+    7995          46 :           std::scoped_lock lock(mutex_controller_tracker_switch_time_);
+    7996             : 
+    7997             :           // update the time (used in failsafe)
+    7998          23 :           controller_tracker_switch_time_ = ros::Time::now();
+    7999             :         }
+    8000             : 
+    8001             :         // super important, switch the active tracker idx
+    8002             :         try {
+    8003             : 
+    8004          23 :           ROS_INFO("[ControlManager]: deactivating '%s'", _tracker_names_[active_tracker_idx_].c_str());
+    8005          23 :           tracker_list_[active_tracker_idx_]->deactivate();
+    8006             : 
+    8007             :           // if switching from null tracker, re-activate the already active the controller
+    8008          23 :           if (active_tracker_idx_ == _null_tracker_idx_) {
+    8009             : 
+    8010           7 :             ROS_INFO("[ControlManager]: reactivating '%s' due to switching from 'NullTracker'", _controller_names_[active_controller_idx_].c_str());
+    8011             :             {
+    8012          14 :               std::scoped_lock lock(mutex_controller_list_);
+    8013             : 
+    8014           7 :               initializeControlOutput();
+    8015             : 
+    8016          14 :               auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    8017             : 
+    8018           7 :               controller_list_[active_controller_idx_]->activate(last_control_output);
+    8019             : 
+    8020             :               {
+    8021          14 :                 std::scoped_lock lock(mutex_controller_tracker_switch_time_);
+    8022             : 
+    8023             :                 // update the time (used in failsafe)
+    8024           7 :                 controller_tracker_switch_time_ = ros::Time::now();
+    8025             :               }
+    8026             :             }
+    8027             : 
+    8028             :             // if switching to null tracker, deactivate the active controller
+    8029          16 :           } else if (new_tracker_idx == _null_tracker_idx_) {
+    8030             : 
+    8031           5 :             ROS_INFO("[ControlManager]: deactivating '%s' due to switching to 'NullTracker'", _controller_names_[active_controller_idx_].c_str());
+    8032             :             {
+    8033          10 :               std::scoped_lock lock(mutex_controller_list_);
+    8034             : 
+    8035           5 :               controller_list_[active_controller_idx_]->deactivate();
+    8036             :             }
+    8037             : 
+    8038             :             {
+    8039           5 :               std::scoped_lock lock(mutex_last_tracker_cmd_);
+    8040             : 
+    8041           5 :               last_tracker_cmd_ = {};
+    8042             :             }
+    8043             : 
+    8044           5 :             initializeControlOutput();
+    8045             :           }
+    8046             : 
+    8047          23 :           active_tracker_idx_ = new_tracker_idx.value();
+    8048             :         }
+    8049           0 :         catch (std::runtime_error& exrun) {
+    8050           0 :           ROS_ERROR("[ControlManager]: could not deactivate the tracker '%s'", _tracker_names_[active_tracker_idx_].c_str());
+    8051             :         }
+    8052             :       }
+    8053             :     }
+    8054           0 :     catch (std::runtime_error& exrun) {
+    8055           0 :       ROS_ERROR("[ControlManager]: error during activation of the tracker '%s'", tracker_name.c_str());
+    8056           0 :       ROS_ERROR("[ControlManager]: exception: '%s'", exrun.what());
+    8057             :     }
+    8058             :   }
+    8059             : 
+    8060          23 :   return std::tuple(true, ss.str());
+    8061             : }
+    8062             : 
+    8063             : //}
+    8064             : 
+    8065             : /* switchController() //{ */
+    8066             : 
+    8067          23 : std::tuple<bool, std::string> ControlManager::switchController(const std::string& controller_name) {
+    8068          69 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("switchController");
+    8069          69 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::switchController", scope_timer_logger_, scope_timer_enabled_);
+    8070             : 
+    8071             :   // copy member variables
+    8072          46 :   auto last_control_output   = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    8073          46 :   auto last_tracker_cmd      = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    8074          23 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    8075             : 
+    8076          46 :   std::stringstream ss;
+    8077             : 
+    8078          23 :   if (!got_uav_state_) {
+    8079             : 
+    8080           0 :     ss << "can not switch controller, missing odometry!";
+    8081           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    8082           0 :     return std::tuple(false, ss.str());
+    8083             :   }
+    8084             : 
+    8085          23 :   if (_state_input_ == INPUT_UAV_STATE && _odometry_innovation_check_enabled_ && !sh_odometry_innovation_.hasMsg()) {
+    8086             : 
+    8087           0 :     ss << "can not switch controller, missing odometry innovation!";
+    8088           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    8089           0 :     return std::tuple(false, ss.str());
+    8090             :   }
+    8091             : 
+    8092          23 :   auto new_controller_idx = idxInVector(controller_name, _controller_names_);
+    8093             : 
+    8094             :   // check if the controller exists
+    8095          23 :   if (!new_controller_idx) {
+    8096           0 :     ss << "the controller '" << controller_name << "' does not exist!";
+    8097           0 :     ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    8098           0 :     return std::tuple(false, ss.str());
+    8099             :   }
+    8100             : 
+    8101             :   // check if the controller is not active
+    8102          23 :   if (new_controller_idx.value() == active_controller_idx) {
+    8103             : 
+    8104           5 :     ss << "not switching, the controller '" << controller_name << "' is already active!";
+    8105           5 :     ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    8106           5 :     return std::tuple(true, ss.str());
+    8107             :   }
+    8108             : 
+    8109             :   {
+    8110          18 :     std::scoped_lock lock(mutex_controller_list_);
+    8111             : 
+    8112             :     try {
+    8113             : 
+    8114          18 :       ROS_INFO("[ControlManager]: activating the controller '%s'", _controller_names_[new_controller_idx.value()].c_str());
+    8115          18 :       if (!controller_list_[new_controller_idx.value()]->activate(last_control_output)) {
+    8116             : 
+    8117           0 :         ss << "the controller '" << controller_name << "' was not activated";
+    8118           0 :         ROS_ERROR_STREAM("[ControlManager]: " << ss.str());
+    8119           0 :         return std::tuple(false, ss.str());
+    8120             : 
+    8121             :       } else {
+    8122             : 
+    8123          18 :         ss << "the controller '" << controller_name << "' was activated";
+    8124          18 :         ROS_INFO_STREAM("[ControlManager]: " << ss.str());
+    8125             : 
+    8126          18 :         ROS_INFO("[ControlManager]: triggering hover after switching to '%s', re-activating '%s'", _controller_names_[new_controller_idx.value()].c_str(),
+    8127             :                  _tracker_names_[active_tracker_idx_].c_str());
+    8128             : 
+    8129             :         // reactivate the current tracker
+    8130             :         // TODO this is not the most elegant way to restart the tracker after a controller switch
+    8131             :         // but it serves the purpose
+    8132             :         {
+    8133          18 :           std::scoped_lock lock(mutex_tracker_list_);
+    8134             : 
+    8135          18 :           tracker_list_[active_tracker_idx_]->deactivate();
+    8136          18 :           tracker_list_[active_tracker_idx_]->activate({});
+    8137             :         }
+    8138             : 
+    8139             :         {
+    8140          36 :           std::scoped_lock lock(mutex_controller_tracker_switch_time_);
+    8141             : 
+    8142             :           // update the time (used in failsafe)
+    8143          18 :           controller_tracker_switch_time_ = ros::Time::now();
+    8144             :         }
+    8145             : 
+    8146             :         // super important, switch the active controller idx
+    8147             :         try {
+    8148             : 
+    8149          18 :           controller_list_[active_controller_idx_]->deactivate();
+    8150          18 :           active_controller_idx_ = new_controller_idx.value();
+    8151             :         }
+    8152           0 :         catch (std::runtime_error& exrun) {
+    8153           0 :           ROS_ERROR("[ControlManager]: could not deactivate controller '%s'", _controller_names_[active_controller_idx_].c_str());
+    8154             :         }
+    8155             :       }
+    8156             :     }
+    8157           0 :     catch (std::runtime_error& exrun) {
+    8158           0 :       ROS_ERROR("[ControlManager]: error during activation of controller '%s'", controller_name.c_str());
+    8159           0 :       ROS_ERROR("[ControlManager]: exception: '%s'", exrun.what());
+    8160             :     }
+    8161             :   }
+    8162             : 
+    8163          18 :   mrs_msgs::DynamicsConstraintsSrvRequest sanitized_constraints;
+    8164             : 
+    8165             :   {
+    8166          18 :     std::scoped_lock lock(mutex_constraints_);
+    8167             : 
+    8168          18 :     sanitized_constraints_ = current_constraints_;
+    8169          18 :     sanitized_constraints  = sanitized_constraints_;
+    8170             :   }
+    8171             : 
+    8172          18 :   setConstraintsToControllers(sanitized_constraints);
+    8173             : 
+    8174          18 :   return std::tuple(true, ss.str());
+    8175             : }
+    8176             : 
+    8177             : //}
+    8178             : 
+    8179             : /* updateTrackers() //{ */
+    8180             : 
+    8181        6839 : void ControlManager::updateTrackers(void) {
+    8182       13678 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("updateTrackers");
+    8183       13678 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::updateTrackers", scope_timer_logger_, scope_timer_enabled_);
+    8184             : 
+    8185             :   // copy member variables
+    8186        6839 :   auto uav_state           = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    8187        6839 :   auto last_control_output = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    8188        6839 :   auto active_tracker_idx  = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    8189             : 
+    8190             :   // --------------------------------------------------------------
+    8191             :   // |                     Update the trackers                    |
+    8192             :   // --------------------------------------------------------------
+    8193             : 
+    8194           0 :   std::optional<mrs_msgs::TrackerCommand> tracker_command;
+    8195             : 
+    8196             :   // for each tracker
+    8197       47873 :   for (size_t i = 0; i < tracker_list_.size(); i++) {
+    8198             : 
+    8199       41034 :     if (i == active_tracker_idx) {
+    8200             : 
+    8201             :       try {
+    8202        6839 :         std::scoped_lock lock(mutex_tracker_list_);
+    8203             : 
+    8204             :         // active tracker => update and retrieve the command
+    8205        6839 :         tracker_command = tracker_list_[i]->update(uav_state, last_control_output);
+    8206             :       }
+    8207           0 :       catch (std::runtime_error& exrun) {
+    8208             : 
+    8209           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception while updating the active tracker (%s)", _tracker_names_[active_tracker_idx].c_str());
+    8210           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception: '%s'", exrun.what());
+    8211           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: triggering eland due to an exception in the active tracker");
+    8212             : 
+    8213           0 :         eland();
+    8214             :       }
+    8215             : 
+    8216             :     } else {
+    8217             : 
+    8218             :       try {
+    8219       34195 :         std::scoped_lock lock(mutex_tracker_list_);
+    8220             : 
+    8221             :         // nonactive tracker => just update without retrieving the command
+    8222       34195 :         tracker_list_[i]->update(uav_state, last_control_output);
+    8223             :       }
+    8224           0 :       catch (std::runtime_error& exrun) {
+    8225             : 
+    8226           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception while updating the tracker '%s'", _tracker_names_[i].c_str());
+    8227           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception: '%s'", exrun.what());
+    8228           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: triggering eland due to an exception in the tracker");
+    8229             : 
+    8230           0 :         eland();
+    8231             :       }
+    8232             :     }
+    8233             :   }
+    8234             : 
+    8235        6839 :   if (active_tracker_idx == _null_tracker_idx_) {
+    8236        1374 :     return;
+    8237             :   }
+    8238             : 
+    8239        5465 :   if (validateTrackerCommand(tracker_command, "ControlManager", "tracker_command")) {
+    8240             : 
+    8241       10930 :     std::scoped_lock lock(mutex_last_tracker_cmd_);
+    8242             : 
+    8243        5465 :     last_tracker_cmd_ = tracker_command;
+    8244             : 
+    8245             :     // | --------- fill in the potentially missing header --------- |
+    8246             : 
+    8247        5465 :     if (last_tracker_cmd_->header.frame_id == "") {
+    8248           0 :       last_tracker_cmd_->header.frame_id = uav_state.header.frame_id;
+    8249             :     }
+    8250             : 
+    8251        5465 :     if (last_tracker_cmd_->header.stamp == ros::Time(0)) {
+    8252           0 :       last_tracker_cmd_->header.stamp = ros::Time::now();
+    8253             :     }
+    8254             : 
+    8255             :   } else {
+    8256             : 
+    8257           0 :     if (active_tracker_idx != _null_tracker_idx_) {
+    8258             : 
+    8259           0 :       if (active_tracker_idx == _ehover_tracker_idx_) {
+    8260             : 
+    8261           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: the ehover tracker '%s' returned empty or invalid command!", _tracker_names_[active_tracker_idx].c_str());
+    8262             : 
+    8263           0 :         failsafe();
+    8264             : 
+    8265             :       } else {
+    8266             : 
+    8267           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: the tracker '%s' returned empty or invalid command!", _tracker_names_[active_tracker_idx].c_str());
+    8268             : 
+    8269           0 :         if (_tracker_error_action_ == ELAND_STR) {
+    8270           0 :           eland();
+    8271           0 :         } else if (_tracker_error_action_ == EHOVER_STR) {
+    8272           0 :           ehover();
+    8273             :         } else {
+    8274           0 :           failsafe();
+    8275             :         }
+    8276             :       }
+    8277             : 
+    8278             :     } else {
+    8279             : 
+    8280           0 :       std::scoped_lock lock(mutex_last_tracker_cmd_);
+    8281             : 
+    8282           0 :       last_tracker_cmd_ = tracker_command;
+    8283             :     }
+    8284             :   }
+    8285             : }
+    8286             : 
+    8287             : //}
+    8288             : 
+    8289             : /* updateControllers() //{ */
+    8290             : 
+    8291        8237 : void ControlManager::updateControllers(const mrs_msgs::UavState& uav_state) {
+    8292       16474 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("updateControllers");
+    8293       16474 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::updateControllers", scope_timer_logger_, scope_timer_enabled_);
+    8294             : 
+    8295             :   // copy member variables
+    8296        8237 :   auto last_tracker_cmd      = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    8297        8237 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    8298             : 
+    8299             :   // | ----------------- update the controllers ----------------- |
+    8300             : 
+    8301             :   // the trackers are not running
+    8302        8237 :   if (!last_tracker_cmd) {
+    8303             : 
+    8304        1374 :     ROS_DEBUG_THROTTLE(1.0, "[ControlManager]: tracker command is empty, giving controller just the uav_state");
+    8305             : 
+    8306             :     // give the controllers current uav state
+    8307             :     {
+    8308        2748 :       std::scoped_lock lock(mutex_controller_list_);
+    8309             : 
+    8310             :       // nonactive controller => just update without retrieving the command
+    8311        8244 :       for (int i = 0; i < int(controller_list_.size()); i++) {
+    8312        6870 :         controller_list_[i]->updateInactive(uav_state, last_tracker_cmd);
+    8313             :       }
+    8314             :     }
+    8315             : 
+    8316        1374 :     return;
+    8317             :   }
+    8318             : 
+    8319       13726 :   Controller::ControlOutput control_output;
+    8320             : 
+    8321             :   // for each controller
+    8322       41178 :   for (size_t i = 0; i < controller_list_.size(); i++) {
+    8323             : 
+    8324       34315 :     if (i == active_controller_idx) {
+    8325             : 
+    8326             :       try {
+    8327        6863 :         std::scoped_lock lock(mutex_controller_list_);
+    8328             : 
+    8329             :         // active controller => update and retrieve the command
+    8330        6863 :         control_output = controller_list_[active_controller_idx]->updateActive(uav_state, last_tracker_cmd.value());
+    8331             :       }
+    8332           0 :       catch (std::runtime_error& exrun) {
+    8333             : 
+    8334           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception while updating the active controller (%s)", _controller_names_[active_controller_idx].c_str());
+    8335           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception: '%s'", exrun.what());
+    8336             : 
+    8337           0 :         if (eland_triggered_) {
+    8338             : 
+    8339           0 :           ROS_ERROR_THROTTLE(1.0, "[ControlManager]: triggering failsafe due to an exception in the active controller (eland is already active)");
+    8340           0 :           failsafe();
+    8341             : 
+    8342             :         } else {
+    8343             : 
+    8344           0 :           ROS_ERROR_THROTTLE(1.0, "[ControlManager]: triggering eland due to an exception in the active controller");
+    8345           0 :           eland();
+    8346             :         }
+    8347             :       }
+    8348             : 
+    8349             :     } else {
+    8350             : 
+    8351             :       try {
+    8352       54904 :         std::scoped_lock lock(mutex_controller_list_);
+    8353             : 
+    8354             :         // nonactive controller => just update without retrieving the command
+    8355       27452 :         controller_list_[i]->updateInactive(uav_state, last_tracker_cmd);
+    8356             :       }
+    8357           0 :       catch (std::runtime_error& exrun) {
+    8358             : 
+    8359           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception while updating the controller '%s'", _controller_names_[i].c_str());
+    8360           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: exception: '%s'", exrun.what());
+    8361           0 :         ROS_ERROR_THROTTLE(1.0, "[ControlManager]: triggering eland (somebody should notice this)");
+    8362             : 
+    8363           0 :         eland();
+    8364             :       }
+    8365             :     }
+    8366             :   }
+    8367             : 
+    8368             :   // normally, the active controller returns a valid command
+    8369        6863 :   if (validateControlOutput(control_output, _hw_api_inputs_, "ControlManager", "control_output")) {
+    8370             : 
+    8371        6863 :     mrs_lib::set_mutexed(mutex_last_control_output_, control_output, last_control_output_);
+    8372             : 
+    8373             :     // but it can return an empty command, due to some critical internal error
+    8374             :     // which means we should trigger the failsafe landing
+    8375             :   } else {
+    8376             : 
+    8377             :     // only if the controller is still active, trigger escalating failsafe
+    8378             :     // if not active, we don't care, we should not ask the controller for
+    8379             :     // the result anyway -> this could mean a race condition occured
+    8380             :     // like it once happend during landing
+    8381           0 :     bool controller_status = false;
+    8382             : 
+    8383             :     {
+    8384           0 :       std::scoped_lock lock(mutex_controller_list_);
+    8385             : 
+    8386           0 :       controller_status = controller_list_[active_controller_idx]->getStatus().active;
+    8387             :     }
+    8388             : 
+    8389           0 :     if (controller_status) {
+    8390             : 
+    8391           0 :       if (active_controller_idx_ == _failsafe_controller_idx_) {
+    8392             : 
+    8393           0 :         ROS_ERROR("[ControlManager]: failsafe controller returned empty command, disabling control");
+    8394             : 
+    8395           0 :         toggleOutput(false);
+    8396             : 
+    8397           0 :       } else if (active_controller_idx_ == _eland_controller_idx_) {
+    8398             : 
+    8399           0 :         ROS_ERROR("[ControlManager]: triggering failsafe, the emergency controller returned empty or invalid command");
+    8400             : 
+    8401           0 :         failsafe();
+    8402             : 
+    8403             :       } else {
+    8404             : 
+    8405           0 :         ROS_ERROR("[ControlManager]: triggering eland, the controller returned empty or invalid command");
+    8406             : 
+    8407           0 :         eland();
+    8408             :       }
+    8409             :     }
+    8410             :   }
+    8411             : }
+    8412             : 
+    8413             : //}
+    8414             : 
+    8415             : /* publish() //{ */
+    8416             : 
+    8417        8237 : void ControlManager::publish(void) {
+    8418       16474 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("publish");
+    8419       16474 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::publish", scope_timer_logger_, scope_timer_enabled_);
+    8420             : 
+    8421             :   // copy member variables
+    8422        8237 :   auto last_control_output   = mrs_lib::get_mutexed(mutex_last_control_output_, last_control_output_);
+    8423        8237 :   auto last_tracker_cmd      = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    8424        8237 :   auto active_tracker_idx    = mrs_lib::get_mutexed(mutex_tracker_list_, active_tracker_idx_);
+    8425        8237 :   auto active_controller_idx = mrs_lib::get_mutexed(mutex_controller_list_, active_controller_idx_);
+    8426        8237 :   auto uav_state             = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    8427             : 
+    8428        8237 :   publishControlReferenceOdom(last_tracker_cmd, last_control_output);
+    8429             : 
+    8430             :   // --------------------------------------------------------------
+    8431             :   // |                 Publish the control command                |
+    8432             :   // --------------------------------------------------------------
+    8433             : 
+    8434        8237 :   mrs_msgs::HwApiAttitudeCmd attitude_target;
+    8435        8237 :   attitude_target.stamp = ros::Time::now();
+    8436             : 
+    8437        8237 :   mrs_msgs::HwApiAttitudeRateCmd attitude_rate_target;
+    8438        8237 :   attitude_rate_target.stamp = ros::Time::now();
+    8439             : 
+    8440        8237 :   if (!output_enabled_) {
+    8441             : 
+    8442         937 :     ROS_WARN_THROTTLE(1.0, "[ControlManager]: output is disabled");
+    8443             : 
+    8444        7300 :   } else if (active_tracker_idx == _null_tracker_idx_) {
+    8445             : 
+    8446         438 :     ROS_WARN_THROTTLE(5.0, "[ControlManager]: 'NullTracker' is active, not controlling");
+    8447             : 
+    8448             :     Controller::HwApiOutputVariant output =
+    8449         876 :         initializeDefaultOutput(_hw_api_inputs_, uav_state, _min_throttle_null_tracker_, common_handlers_->throttle_model.n_motors);
+    8450             : 
+    8451             :     {
+    8452         876 :       std::scoped_lock lock(mutex_last_control_output_);
+    8453             : 
+    8454         438 :       last_control_output_.control_output = output;
+    8455             :     }
+    8456             : 
+    8457         438 :     control_output_publisher_.publish(output);
+    8458             : 
+    8459        6862 :   } else if (active_tracker_idx != _null_tracker_idx_ && !last_control_output.control_output) {
+    8460             : 
+    8461           0 :     ROS_WARN_THROTTLE(1.0, "[ControlManager]: the controller '%s' returned nil command, not publishing anything",
+    8462             :                       _controller_names_[active_controller_idx].c_str());
+    8463             : 
+    8464             :     Controller::HwApiOutputVariant output =
+    8465           0 :         initializeDefaultOutput(_hw_api_inputs_, uav_state, _min_throttle_null_tracker_, common_handlers_->throttle_model.n_motors);
+    8466             : 
+    8467           0 :     control_output_publisher_.publish(output);
+    8468             : 
+    8469        6862 :   } else if (last_control_output.control_output) {
+    8470             : 
+    8471        6862 :     if (validateHwApiAttitudeCmd(attitude_target, "ControlManager", "last_control_output.control_output")) {
+    8472        6862 :       control_output_publisher_.publish(last_control_output.control_output.value());
+    8473             :     } else {
+    8474           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: the attitude cmd is not valid just before publishing!");
+    8475           0 :       return;
+    8476             :     }
+    8477             : 
+    8478             :   } else {
+    8479           0 :     ROS_ERROR_THROTTLE(1.0, "[ControlManager]: not publishing a control command");
+    8480             :   }
+    8481             : 
+    8482             :   // | ----------- publish the controller diagnostics ----------- |
+    8483             : 
+    8484        8237 :   ph_controller_diagnostics_.publish(last_control_output.diagnostics);
+    8485             : 
+    8486             :   // | --------- publish the applied throttle and thrust -------- |
+    8487             : 
+    8488        8237 :   auto throttle = extractThrottle(last_control_output);
+    8489             : 
+    8490        8237 :   if (throttle) {
+    8491             : 
+    8492             :     {
+    8493        7329 :       std_msgs::Float64 msg;
+    8494        7329 :       msg.data = throttle.value();
+    8495        7329 :       ph_throttle_.publish(msg);
+    8496             :     }
+    8497             : 
+    8498        7329 :     double thrust = mrs_lib::quadratic_throttle_model::throttleToForce(common_handlers_->throttle_model, throttle.value());
+    8499             : 
+    8500             :     {
+    8501        7329 :       std_msgs::Float64 msg;
+    8502        7329 :       msg.data = thrust;
+    8503        7329 :       ph_thrust_.publish(msg);
+    8504             :     }
+    8505             :   }
+    8506             : 
+    8507             :   // | ----------------- publish tracker command ---------------- |
+    8508             : 
+    8509        8237 :   if (last_tracker_cmd) {
+    8510        6862 :     ph_tracker_cmd_.publish(last_tracker_cmd.value());
+    8511             :   }
+    8512             : 
+    8513             :   // | --------------- publish the odometry input --------------- |
+    8514             : 
+    8515        8237 :   if (last_control_output.control_output) {
+    8516             : 
+    8517       14658 :     mrs_msgs::EstimatorInput msg;
+    8518             : 
+    8519        7329 :     msg.header.frame_id = _uav_name_ + "/fcu";
+    8520        7329 :     msg.header.stamp    = ros::Time::now();
+    8521             : 
+    8522        7329 :     if (last_control_output.desired_unbiased_acceleration) {
+    8523        5427 :       msg.control_acceleration.x = last_control_output.desired_unbiased_acceleration.value()[0];
+    8524        5427 :       msg.control_acceleration.y = last_control_output.desired_unbiased_acceleration.value()[1];
+    8525        5427 :       msg.control_acceleration.z = last_control_output.desired_unbiased_acceleration.value()[2];
+    8526             :     }
+    8527             : 
+    8528        7329 :     if (last_control_output.desired_heading_rate) {
+    8529        5427 :       msg.control_hdg_rate = last_control_output.desired_heading_rate.value();
+    8530             :     }
+    8531             : 
+    8532        7329 :     if (last_control_output.desired_unbiased_acceleration) {
+    8533        5427 :       ph_mrs_odom_input_.publish(msg);
+    8534             :     }
+    8535             :   }
+    8536             : }
+    8537             : 
+    8538             : //}
+    8539             : 
+    8540             : /* deployParachute() //{ */
+    8541             : 
+    8542           0 : std::tuple<bool, std::string> ControlManager::deployParachute(void) {
+    8543             :   // if not enabled, return false
+    8544           0 :   if (!_parachute_enabled_) {
+    8545             : 
+    8546           0 :     std::stringstream ss;
+    8547           0 :     ss << "can not deploy parachute, it is disabled";
+    8548           0 :     return std::tuple(false, ss.str());
+    8549             :   }
+    8550             : 
+    8551             :   // we can not disarm if the drone is not in offboard mode
+    8552             :   // this is super important!
+    8553           0 :   if (!isOffboard()) {
+    8554             : 
+    8555           0 :     std::stringstream ss;
+    8556           0 :     ss << "can not deploy parachute, not in offboard mode";
+    8557           0 :     return std::tuple(false, ss.str());
+    8558             :   }
+    8559             : 
+    8560             :   // call the parachute service
+    8561           0 :   bool succ = parachuteSrv();
+    8562             : 
+    8563             :   // if the deployment was successful,
+    8564           0 :   if (succ) {
+    8565             : 
+    8566           0 :     arming(false);
+    8567             : 
+    8568           0 :     std::stringstream ss;
+    8569           0 :     ss << "parachute deployed";
+    8570             : 
+    8571           0 :     return std::tuple(true, ss.str());
+    8572             : 
+    8573             :   } else {
+    8574             : 
+    8575           0 :     std::stringstream ss;
+    8576           0 :     ss << "error during deployment of parachute";
+    8577             : 
+    8578           0 :     return std::tuple(false, ss.str());
+    8579             :   }
+    8580             : }
+    8581             : 
+    8582             : //}
+    8583             : 
+    8584             : /* velocityReferenceToReference() //{ */
+    8585             : 
+    8586           0 : mrs_msgs::ReferenceStamped ControlManager::velocityReferenceToReference(const mrs_msgs::VelocityReferenceStamped& vel_reference) {
+    8587           0 :   auto last_tracker_cmd    = mrs_lib::get_mutexed(mutex_last_tracker_cmd_, last_tracker_cmd_);
+    8588           0 :   auto uav_state           = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    8589           0 :   auto current_constraints = mrs_lib::get_mutexed(mutex_constraints_, current_constraints_);
+    8590             : 
+    8591           0 :   mrs_msgs::ReferenceStamped reference_out;
+    8592             : 
+    8593           0 :   reference_out.header = vel_reference.header;
+    8594             : 
+    8595           0 :   if (vel_reference.reference.use_heading) {
+    8596           0 :     reference_out.reference.heading = vel_reference.reference.heading;
+    8597           0 :   } else if (vel_reference.reference.use_heading_rate) {
+    8598           0 :     reference_out.reference.heading = mrs_lib::AttitudeConverter(uav_state.pose.orientation).getHeading() + vel_reference.reference.use_heading_rate;
+    8599             :   } else {
+    8600           0 :     reference_out.reference.heading = mrs_lib::AttitudeConverter(uav_state.pose.orientation).getHeading();
+    8601             :   }
+    8602             : 
+    8603           0 :   if (vel_reference.reference.use_altitude) {
+    8604           0 :     reference_out.reference.position.z = vel_reference.reference.altitude;
+    8605             :   } else {
+    8606             : 
+    8607           0 :     double stopping_time_z = 0;
+    8608             : 
+    8609           0 :     if (vel_reference.reference.velocity.x >= 0) {
+    8610           0 :       stopping_time_z = 1.5 * (fabs(vel_reference.reference.velocity.z) / current_constraints.constraints.vertical_ascending_acceleration) + 1.0;
+    8611             :     } else {
+    8612           0 :       stopping_time_z = 1.5 * (fabs(vel_reference.reference.velocity.z) / current_constraints.constraints.vertical_descending_acceleration) + 1.0;
+    8613             :     }
+    8614             : 
+    8615           0 :     reference_out.reference.position.z = last_tracker_cmd->position.z + vel_reference.reference.velocity.z * stopping_time_z;
+    8616             :   }
+    8617             : 
+    8618             :   {
+    8619           0 :     double stopping_time_x = 1.5 * (fabs(vel_reference.reference.velocity.x) / current_constraints.constraints.horizontal_acceleration) + 1.0;
+    8620           0 :     double stopping_time_y = 1.5 * (fabs(vel_reference.reference.velocity.y) / current_constraints.constraints.horizontal_acceleration) + 1.0;
+    8621             : 
+    8622           0 :     reference_out.reference.position.x = last_tracker_cmd->position.x + vel_reference.reference.velocity.x * stopping_time_x;
+    8623           0 :     reference_out.reference.position.y = last_tracker_cmd->position.y + vel_reference.reference.velocity.y * stopping_time_y;
+    8624             :   }
+    8625             : 
+    8626           0 :   return reference_out;
+    8627             : }
+    8628             : 
+    8629             : //}
+    8630             : 
+    8631             : /* publishControlReferenceOdom() //{ */
+    8632             : 
+    8633        8237 : void ControlManager::publishControlReferenceOdom([[maybe_unused]] const std::optional<mrs_msgs::TrackerCommand>& tracker_command,
+    8634             :                                                  [[maybe_unused]] const Controller::ControlOutput&               control_output) {
+    8635        8237 :   if (!tracker_command || !control_output.control_output) {
+    8636        1375 :     return;
+    8637             :   }
+    8638             : 
+    8639       13724 :   auto uav_state = mrs_lib::get_mutexed(mutex_uav_state_, uav_state_);
+    8640             : 
+    8641       13724 :   nav_msgs::Odometry msg;
+    8642             : 
+    8643        6862 :   msg.header = tracker_command->header;
+    8644             : 
+    8645        6862 :   if (tracker_command->use_position_horizontal) {
+    8646        6862 :     msg.pose.pose.position.x = tracker_command->position.x;
+    8647        6862 :     msg.pose.pose.position.y = tracker_command->position.y;
+    8648             :   } else {
+    8649           0 :     msg.pose.pose.position.x = uav_state.pose.position.x;
+    8650           0 :     msg.pose.pose.position.y = uav_state.pose.position.y;
+    8651             :   }
+    8652             : 
+    8653        6862 :   if (tracker_command->use_position_vertical) {
+    8654        6862 :     msg.pose.pose.position.z = tracker_command->position.z;
+    8655             :   } else {
+    8656           0 :     msg.pose.pose.position.z = uav_state.pose.position.z;
+    8657             :   }
+    8658             : 
+    8659             :   // transform the velocity in the reference to the child_frame
+    8660        6862 :   if (tracker_command->use_velocity_horizontal || tracker_command->use_velocity_vertical) {
+    8661             : 
+    8662        6862 :     msg.child_frame_id = _uav_name_ + "/" + _body_frame_;
+    8663             : 
+    8664       13724 :     geometry_msgs::Vector3Stamped velocity;
+    8665        6862 :     velocity.header = tracker_command->header;
+    8666             : 
+    8667        6862 :     if (tracker_command->use_velocity_horizontal) {
+    8668        6862 :       velocity.vector.x = tracker_command->velocity.x;
+    8669        6862 :       velocity.vector.y = tracker_command->velocity.y;
+    8670             :     }
+    8671             : 
+    8672        6862 :     if (tracker_command->use_velocity_vertical) {
+    8673        6862 :       velocity.vector.z = tracker_command->velocity.z;
+    8674             :     }
+    8675             : 
+    8676       13724 :     auto res = transformer_->transformSingle(velocity, msg.child_frame_id);
+    8677             : 
+    8678        6862 :     if (res) {
+    8679        6862 :       msg.twist.twist.linear.x = res.value().vector.x;
+    8680        6862 :       msg.twist.twist.linear.y = res.value().vector.y;
+    8681        6862 :       msg.twist.twist.linear.z = res.value().vector.z;
+    8682             :     } else {
+    8683           0 :       ROS_ERROR_THROTTLE(1.0, "[ControlManager]: could not transform the reference speed from '%s' to '%s'", velocity.header.frame_id.c_str(),
+    8684             :                          msg.child_frame_id.c_str());
+    8685             :     }
+    8686             :   }
+    8687             : 
+    8688             :   // fill in the orientation or heading
+    8689        6862 :   if (control_output.desired_orientation) {
+    8690        5427 :     msg.pose.pose.orientation = mrs_lib::AttitudeConverter(control_output.desired_orientation.value());
+    8691        1435 :   } else if (tracker_command->use_heading) {
+    8692        1435 :     msg.pose.pose.orientation = mrs_lib::AttitudeConverter(0, 0, tracker_command->heading);
+    8693             :   }
+    8694             : 
+    8695             :   // fill in the attitude rate
+    8696        6862 :   if (std::holds_alternative<mrs_msgs::HwApiAttitudeRateCmd>(control_output.control_output.value())) {
+    8697             : 
+    8698        5427 :     auto attitude_cmd = std::get<mrs_msgs::HwApiAttitudeRateCmd>(control_output.control_output.value());
+    8699             : 
+    8700        5427 :     msg.twist.twist.angular.x = attitude_cmd.body_rate.x;
+    8701        5427 :     msg.twist.twist.angular.y = attitude_cmd.body_rate.y;
+    8702        5427 :     msg.twist.twist.angular.z = attitude_cmd.body_rate.z;
+    8703             :   }
+    8704             : 
+    8705        6862 :   ph_control_reference_odom_.publish(msg);
+    8706             : }
+    8707             : 
+    8708             : //}
+    8709             : 
+    8710             : /* initializeControlOutput() //{ */
+    8711             : 
+    8712          19 : void ControlManager::initializeControlOutput(void) {
+    8713          19 :   Controller::ControlOutput controller_output;
+    8714             : 
+    8715          19 :   controller_output.diagnostics.total_mass       = _uav_mass_;
+    8716          19 :   controller_output.diagnostics.mass_difference  = 0.0;
+    8717          19 :   controller_output.diagnostics.disturbance_bx_b = _initial_body_disturbance_x_;
+    8718          19 :   controller_output.diagnostics.disturbance_by_b = _initial_body_disturbance_y_;
+    8719          19 :   controller_output.diagnostics.disturbance_wx_w = 0.0;
+    8720          19 :   controller_output.diagnostics.disturbance_wy_w = 0.0;
+    8721          19 :   controller_output.diagnostics.disturbance_bx_w = 0.0;
+    8722          19 :   controller_output.diagnostics.disturbance_by_w = 0.0;
+    8723          19 :   controller_output.diagnostics.controller       = "none";
+    8724             : 
+    8725          19 :   mrs_lib::set_mutexed(mutex_last_control_output_, controller_output, last_control_output_);
+    8726          19 : }
+    8727             : 
+    8728             : //}
+    8729             : 
+    8730             : }  // namespace control_manager
+    8731             : 
+    8732             : }  // namespace mrs_uav_managers
+    8733             : 
+    8734             : #include <pluginlib/class_list_macros.h>
+    8735           7 : PLUGINLIB_EXPORT_CLASS(mrs_uav_managers::control_manager::ControlManager, nodelet::Nodelet)
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/index-sort-f.html b/mrs_uav_managers/src/control_manager/index-sort-f.html new file mode 100644 index 0000000000..8594f090d0 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_managerHitTotalCoverage
Test:coverage.infoLines:1723371246.4 %
Date:2023-11-29 14:09:54Functions:6412352.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
output_publisher.cpp +
51.2%51.2%
+
51.2 %22 / 4341.7 %5 / 12
control_manager.cpp +
46.4%46.4%
+
46.4 %1701 / 366953.2 %59 / 111
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/index-sort-l.html b/mrs_uav_managers/src/control_manager/index-sort-l.html new file mode 100644 index 0000000000..e24fb073b4 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_managerHitTotalCoverage
Test:coverage.infoLines:1723371246.4 %
Date:2023-11-29 14:09:54Functions:6412352.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
control_manager.cpp +
46.4%46.4%
+
46.4 %1701 / 366953.2 %59 / 111
output_publisher.cpp +
51.2%51.2%
+
51.2 %22 / 4341.7 %5 / 12
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/index.html b/mrs_uav_managers/src/control_manager/index.html new file mode 100644 index 0000000000..e32b2f8dd0 --- /dev/null +++ b/mrs_uav_managers/src/control_manager/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_managerHitTotalCoverage
Test:coverage.infoLines:1723371246.4 %
Date:2023-11-29 14:09:54Functions:6412352.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
control_manager.cpp +
46.4%46.4%
+
46.4 %1701 / 366953.2 %59 / 111
output_publisher.cpp +
51.2%51.2%
+
51.2 %22 / 4341.7 %5 / 12
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/output_publisher.cpp.func-sort-c.html b/mrs_uav_managers/src/control_manager/output_publisher.cpp.func-sort-c.html new file mode 100644 index 0000000000..3bc597502b --- /dev/null +++ b/mrs_uav_managers/src/control_manager/output_publisher.cpp.func-sort-c.html @@ -0,0 +1,120 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/output_publisher.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager - output_publisher.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:224351.2 %
Date:2023-11-29 14:09:54Functions:51241.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisherC2ERN3ros10NodeHandleE7
_ZN16mrs_uav_managers15control_manager15OutputPublisherC2Ev7
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEE1435
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEE5865
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKSt7variantIJN8mrs_msgs17HwApiActuatorCmd_ISaIvEEENS3_21HwApiControlGroupCmd_IS5_EENS3_21HwApiAttitudeRateCmd_IS5_EENS3_17HwApiAttitudeCmd_IS5_EENS3_28HwApiAccelerationHdgRateCmd_IS5_EENS3_24HwApiAccelerationHdgCmd_IS5_EENS3_24HwApiVelocityHdgRateCmd_IS5_EENS3_20HwApiVelocityHdgCmd_IS5_EENS3_17HwApiPositionCmd_IS5_EEEE7300
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/output_publisher.cpp.func.html b/mrs_uav_managers/src/control_manager/output_publisher.cpp.func.html new file mode 100644 index 0000000000..b9894526bd --- /dev/null +++ b/mrs_uav_managers/src/control_manager/output_publisher.cpp.func.html @@ -0,0 +1,120 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/output_publisher.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager - output_publisher.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:224351.2 %
Date:2023-11-29 14:09:54Functions:51241.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs17HwApiActuatorCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs17HwApiAttitudeCmd_ISaIvEEE1435
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs17HwApiPositionCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs20HwApiVelocityHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs21HwApiAttitudeRateCmd_ISaIvEEE5865
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs21HwApiControlGroupCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs24HwApiAccelerationHdgCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs24HwApiVelocityHdgRateCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKN8mrs_msgs28HwApiAccelerationHdgRateCmd_ISaIvEEE0
_ZN16mrs_uav_managers15control_manager15OutputPublisher7publishERKSt7variantIJN8mrs_msgs17HwApiActuatorCmd_ISaIvEEENS3_21HwApiControlGroupCmd_IS5_EENS3_21HwApiAttitudeRateCmd_IS5_EENS3_17HwApiAttitudeCmd_IS5_EENS3_28HwApiAccelerationHdgRateCmd_IS5_EENS3_24HwApiAccelerationHdgCmd_IS5_EENS3_24HwApiVelocityHdgRateCmd_IS5_EENS3_20HwApiVelocityHdgCmd_IS5_EENS3_17HwApiPositionCmd_IS5_EEEE7300
_ZN16mrs_uav_managers15control_manager15OutputPublisherC2ERN3ros10NodeHandleE7
_ZN16mrs_uav_managers15control_manager15OutputPublisherC2Ev7
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/control_manager/output_publisher.cpp.gcov.html b/mrs_uav_managers/src/control_manager/output_publisher.cpp.gcov.html new file mode 100644 index 0000000000..b6aa250b2f --- /dev/null +++ b/mrs_uav_managers/src/control_manager/output_publisher.cpp.gcov.html @@ -0,0 +1,146 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/control_manager/output_publisher.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/control_manager - output_publisher.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:224351.2 %
Date:2023-11-29 14:09:54Functions:51241.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <control_manager/output_publisher.h>
+       2             : 
+       3             : namespace mrs_uav_managers
+       4             : {
+       5             : 
+       6             : namespace control_manager
+       7             : {
+       8             : 
+       9           7 : OutputPublisher::OutputPublisher() {
+      10           7 : }
+      11             : 
+      12           7 : OutputPublisher::OutputPublisher(ros::NodeHandle& nh) {
+      13             : 
+      14           7 :   ph_hw_api_actuator_cmd_              = mrs_lib::PublisherHandler<mrs_msgs::HwApiActuatorCmd>(nh, "hw_api_actuator_cmd_out", 1);
+      15           7 :   ph_hw_api_control_group_cmd_         = mrs_lib::PublisherHandler<mrs_msgs::HwApiControlGroupCmd>(nh, "hw_api_control_group_cmd_out", 1);
+      16           7 :   ph_hw_api_attitude_rate_cmd_         = mrs_lib::PublisherHandler<mrs_msgs::HwApiAttitudeRateCmd>(nh, "hw_api_attitude_rate_cmd_out", 1);
+      17           7 :   ph_hw_api_attitude_cmd_              = mrs_lib::PublisherHandler<mrs_msgs::HwApiAttitudeCmd>(nh, "hw_api_attitude_cmd_out", 1);
+      18           7 :   ph_hw_api_acceleration_hdg_rate_cmd_ = mrs_lib::PublisherHandler<mrs_msgs::HwApiAccelerationHdgRateCmd>(nh, "hw_api_acceleration_hdg_rate_cmd_out", 1);
+      19           7 :   ph_hw_api_acceleration_hdg_cmd_      = mrs_lib::PublisherHandler<mrs_msgs::HwApiAccelerationHdgCmd>(nh, "hw_api_acceleration_hdg_cmd_out", 1);
+      20           7 :   ph_hw_api_velocity_hdg_rate_cmd_     = mrs_lib::PublisherHandler<mrs_msgs::HwApiVelocityHdgRateCmd>(nh, "hw_api_velocity_hdg_rate_cmd_out", 1);
+      21           7 :   ph_hw_api_velocity_hdg_cmd_          = mrs_lib::PublisherHandler<mrs_msgs::HwApiVelocityHdgCmd>(nh, "hw_api_velocity_hdg_cmd_out", 1);
+      22           7 :   ph_hw_api_position_cmd_              = mrs_lib::PublisherHandler<mrs_msgs::HwApiPositionCmd>(nh, "hw_api_position_cmd_out", 1);
+      23           7 : }
+      24             : 
+      25        7300 : void OutputPublisher::publish(const Controller::HwApiOutputVariant& control_output) {
+      26             : 
+      27        7300 :   std::visit(OutputPublisher::PublisherVisitor(this), control_output);
+      28        7300 : }
+      29             : 
+      30             : // | ------------------------- private ------------------------ |
+      31             : 
+      32           0 : void OutputPublisher::publish(const mrs_msgs::HwApiActuatorCmd& msg) {
+      33           0 :   ph_hw_api_actuator_cmd_.publish(msg);
+      34           0 : }
+      35             : 
+      36           0 : void OutputPublisher::publish(const mrs_msgs::HwApiControlGroupCmd& msg) {
+      37           0 :   ph_hw_api_control_group_cmd_.publish(msg);
+      38           0 : }
+      39             : 
+      40        5865 : void OutputPublisher::publish(const mrs_msgs::HwApiAttitudeRateCmd& msg) {
+      41        5865 :   ph_hw_api_attitude_rate_cmd_.publish(msg);
+      42        5865 : }
+      43             : 
+      44        1435 : void OutputPublisher::publish(const mrs_msgs::HwApiAttitudeCmd& msg) {
+      45        1435 :   ph_hw_api_attitude_cmd_.publish(msg);
+      46        1435 : }
+      47             : 
+      48           0 : void OutputPublisher::publish(const mrs_msgs::HwApiAccelerationHdgRateCmd& msg) {
+      49           0 :   ph_hw_api_acceleration_hdg_rate_cmd_.publish(msg);
+      50           0 : }
+      51             : 
+      52           0 : void OutputPublisher::publish(const mrs_msgs::HwApiAccelerationHdgCmd& msg) {
+      53           0 :   ph_hw_api_acceleration_hdg_cmd_.publish(msg);
+      54           0 : }
+      55             : 
+      56           0 : void OutputPublisher::publish(const mrs_msgs::HwApiVelocityHdgRateCmd& msg) {
+      57           0 :   ph_hw_api_velocity_hdg_rate_cmd_.publish(msg);
+      58           0 : }
+      59             : 
+      60           0 : void OutputPublisher::publish(const mrs_msgs::HwApiVelocityHdgCmd& msg) {
+      61           0 :   ph_hw_api_velocity_hdg_cmd_.publish(msg);
+      62           0 : }
+      63             : 
+      64           0 : void OutputPublisher::publish(const mrs_msgs::HwApiPositionCmd& msg) {
+      65           0 :   ph_hw_api_position_cmd_.publish(msg);
+      66           0 : }
+      67             : 
+      68             : }  // namespace control_manager
+      69             : 
+      70             : }  // namespace mrs_uav_managers
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.func-sort-c.html b/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.func-sort-c.html new file mode 100644 index 0000000000..646011df24 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.func-sort-c.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimation_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager - estimation_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:33052862.5 %
Date:2023-11-29 14:09:54Functions:182475.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers18estimation_manager12StateMachine22changeToPreSwitchStateEv0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager14loadConfigFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager17switchToEstimatorERKN5boost10shared_ptrINS_14StateEstimatorEEE0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager19callFailsafeServiceEv0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager23callbackChangeEstimatorERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager24switchToHealthyEstimatorEv0
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers18estimation_manager12StateMachineC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
_ZN16mrs_uav_managers18estimation_manager17EstimationManager19timerInitializationERKN3ros10TimerEventE7
_ZN16mrs_uav_managers18estimation_manager17EstimationManager6onInitEv7
_ZN16mrs_uav_managers18estimation_manager17EstimationManagerC2Ev7
_ZN16mrs_uav_managers18estimation_manager17EstimationManager30callbackToggleServiceCallbacksERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE13
_ZN16mrs_uav_managers18estimation_manager12StateMachine11changeStateERKNS1_9SMState_tE24
_ZNK16mrs_uav_managers18estimation_manager12StateMachine12getPrintNameB5cxx11Ev24
_ZNK16mrs_uav_managers18estimation_manager12StateMachine16getStateAsStringB5cxx11ERKNS1_9SMState_tE48
_ZNK16mrs_uav_managers18estimation_manager17EstimationManager7getNameB5cxx11Ev195
_ZNK16mrs_uav_managers18estimation_manager12StateMachine21getCurrentStateStringB5cxx11Ev939
_ZN16mrs_uav_managers18estimation_manager17EstimationManager23timerPublishDiagnosticsERKN3ros10TimerEventE978
_ZN16mrs_uav_managers18estimation_manager17EstimationManager12timerPublishERKN3ros10TimerEventE9816
_ZN16mrs_uav_managers18estimation_manager17EstimationManager16timerCheckHealthERKN3ros10TimerEventE9816
_ZNK16mrs_uav_managers18estimation_manager12StateMachine10isInTheAirEv9816
_ZNK16mrs_uav_managers18estimation_manager12StateMachine20isInPublishableStateEv10792
_ZNK16mrs_uav_managers18estimation_manager12StateMachine13isInitializedEv20579
_ZNK16mrs_uav_managers18estimation_manager12StateMachine9isInStateERKNS1_9SMState_tE83137
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.func.html b/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.func.html new file mode 100644 index 0000000000..a54e236775 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.func.html @@ -0,0 +1,168 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimation_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager - estimation_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:33052862.5 %
Date:2023-11-29 14:09:54Functions:182475.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers18estimation_manager12StateMachine11changeStateERKNS1_9SMState_tE24
_ZN16mrs_uav_managers18estimation_manager12StateMachine22changeToPreSwitchStateEv0
_ZN16mrs_uav_managers18estimation_manager12StateMachineC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
_ZN16mrs_uav_managers18estimation_manager17EstimationManager12timerPublishERKN3ros10TimerEventE9816
_ZN16mrs_uav_managers18estimation_manager17EstimationManager14loadConfigFileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager16timerCheckHealthERKN3ros10TimerEventE9816
_ZN16mrs_uav_managers18estimation_manager17EstimationManager17switchToEstimatorERKN5boost10shared_ptrINS_14StateEstimatorEEE0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager19callFailsafeServiceEv0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager19timerInitializationERKN3ros10TimerEventE7
_ZN16mrs_uav_managers18estimation_manager17EstimationManager23callbackChangeEstimatorERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager23timerPublishDiagnosticsERKN3ros10TimerEventE978
_ZN16mrs_uav_managers18estimation_manager17EstimationManager24switchToHealthyEstimatorEv0
_ZN16mrs_uav_managers18estimation_manager17EstimationManager30callbackToggleServiceCallbacksERN8std_srvs15SetBoolRequest_ISaIvEEERNS2_16SetBoolResponse_IS4_EE13
_ZN16mrs_uav_managers18estimation_manager17EstimationManager6onInitEv7
_ZN16mrs_uav_managers18estimation_manager17EstimationManagerC2Ev7
_ZNK16mrs_uav_managers18estimation_manager12StateMachine10isInTheAirEv9816
_ZNK16mrs_uav_managers18estimation_manager12StateMachine12getPrintNameB5cxx11Ev24
_ZNK16mrs_uav_managers18estimation_manager12StateMachine13isInitializedEv20579
_ZNK16mrs_uav_managers18estimation_manager12StateMachine16getStateAsStringB5cxx11ERKNS1_9SMState_tE48
_ZNK16mrs_uav_managers18estimation_manager12StateMachine20isInPublishableStateEv10792
_ZNK16mrs_uav_managers18estimation_manager12StateMachine21getCurrentStateStringB5cxx11Ev939
_ZNK16mrs_uav_managers18estimation_manager12StateMachine9isInStateERKNS1_9SMState_tE83137
_ZNK16mrs_uav_managers18estimation_manager17EstimationManager7getNameB5cxx11Ev195
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.gcov.html b/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.gcov.html new file mode 100644 index 0000000000..eb4b4980f3 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimation_manager.cpp.gcov.html @@ -0,0 +1,1305 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimation_manager.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager - estimation_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:33052862.5 %
Date:2023-11-29 14:09:54Functions:182475.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /*//{ includes */
+       2             : #include <ros/ros.h>
+       3             : #include <nodelet/nodelet.h>
+       4             : 
+       5             : #include <pluginlib/class_loader.h>
+       6             : #include <nodelet/loader.h>
+       7             : 
+       8             : #include <geometry_msgs/QuaternionStamped.h>
+       9             : #include <geometry_msgs/Vector3Stamped.h>
+      10             : 
+      11             : #include <nav_msgs/Odometry.h>
+      12             : 
+      13             : #include <std_srvs/Trigger.h>
+      14             : #include <std_srvs/SetBool.h>
+      15             : 
+      16             : #include <mrs_msgs/UavState.h>
+      17             : #include <mrs_msgs/Float64Stamped.h>
+      18             : #include <mrs_msgs/String.h>
+      19             : #include <mrs_msgs/EstimationDiagnostics.h>
+      20             : #include <mrs_msgs/HwApiCapabilities.h>
+      21             : #include <mrs_msgs/ControlManagerDiagnostics.h>
+      22             : 
+      23             : #include <mrs_lib/param_loader.h>
+      24             : #include <mrs_lib/publisher_handler.h>
+      25             : #include <mrs_lib/service_client_handler.h>
+      26             : #include <mrs_lib/transformer.h>
+      27             : #include <mrs_lib/subscribe_handler.h>
+      28             : #include <mrs_lib/gps_conversions.h>
+      29             : #include <mrs_lib/scope_timer.h>
+      30             : 
+      31             : 
+      32             : #include <mrs_uav_managers/state_estimator.h>
+      33             : #include <mrs_uav_managers/agl_estimator.h>
+      34             : #include <mrs_uav_managers/estimation_manager/support.h>
+      35             : #include <mrs_uav_managers/estimation_manager/common_handlers.h>
+      36             : #include <mrs_uav_managers/estimation_manager/private_handlers.h>
+      37             : /*//}*/
+      38             : 
+      39             : namespace mrs_uav_managers
+      40             : {
+      41             : 
+      42             : namespace estimation_manager
+      43             : {
+      44             : 
+      45             : // --------------------------------------------------------------
+      46             : // |                           classes                          |
+      47             : // --------------------------------------------------------------
+      48             : 
+      49             : /*//{ class StateMachine */
+      50             : class StateMachine {
+      51             : 
+      52             :   /*//{ states */
+      53             : public:
+      54             :   typedef enum
+      55             :   {
+      56             : 
+      57             :     UNINITIALIZED_STATE,
+      58             :     INITIALIZED_STATE,
+      59             :     READY_FOR_TAKEOFF_STATE,
+      60             :     TAKING_OFF_STATE,
+      61             :     FLYING_STATE,
+      62             :     HOVER_STATE,
+      63             :     LANDING_STATE,
+      64             :     LANDED_STATE,
+      65             :     ESTIMATOR_SWITCHING_STATE,
+      66             :     DUMMY_STATE,
+      67             :     EMERGENCY_STATE,
+      68             :     FAILSAFE_STATE,
+      69             :     ERROR_STATE
+      70             : 
+      71             :   } SMState_t;
+      72             : 
+      73             :   /*//}*/
+      74             : 
+      75             : public:
+      76          98 :   StateMachine(const std::string& nodelet_name) : nodelet_name_(nodelet_name) {
+      77           7 :   }
+      78             : 
+      79       83137 :   bool isInState(const SMState_t& state) const {
+      80       83137 :     return mrs_lib::get_mutexed(mtx_state_, current_state_) == state;
+      81             :   }
+      82             : 
+      83       20579 :   bool isInitialized() const {
+      84       20579 :     return mrs_lib::get_mutexed(mtx_state_, current_state_) != UNINITIALIZED_STATE;
+      85             :   }
+      86             : 
+      87       10792 :   bool isInPublishableState() const {
+      88       10792 :     const SMState_t current_state = mrs_lib::get_mutexed(mtx_state_, current_state_);
+      89        5193 :     return current_state == READY_FOR_TAKEOFF_STATE || current_state == TAKING_OFF_STATE || current_state == HOVER_STATE || current_state == FLYING_STATE ||
+      90       15987 :            current_state == LANDING_STATE || current_state == DUMMY_STATE || current_state == FAILSAFE_STATE;
+      91             :   }
+      92             : 
+      93        9816 :   bool isInTheAir() const {
+      94        9816 :     const SMState_t current_state = mrs_lib::get_mutexed(mtx_state_, current_state_);
+      95        9816 :     return current_state == TAKING_OFF_STATE || current_state == HOVER_STATE || current_state == FLYING_STATE || current_state == LANDING_STATE;
+      96             :   }
+      97             : 
+      98             :   SMState_t getCurrentState() const {
+      99             :     return mrs_lib::get_mutexed(mtx_state_, current_state_);
+     100             :   }
+     101             : 
+     102         939 :   std::string getCurrentStateString() const {
+     103         939 :     return mrs_lib::get_mutexed(mtx_state_, sm_state_names_[current_state_]);
+     104             :   }
+     105             : 
+     106          48 :   std::string getStateAsString(const SMState_t& state) const {
+     107          48 :     return sm_state_names_[state];
+     108             :   }
+     109             : 
+     110             :   /*//{ changeState() */
+     111          24 :   bool changeState(const SMState_t& target_state) {
+     112             : 
+     113          24 :     if (target_state == current_state_) {
+     114             : 
+     115           0 :       ROS_WARN("[%s]: requested change to same state %s -> %s", getPrintName().c_str(), getStateAsString(current_state_).c_str(),
+     116             :                getStateAsString(target_state).c_str());
+     117           0 :       return true;
+     118             :     }
+     119             : 
+     120          24 :     switch (target_state) {
+     121             : 
+     122           0 :       case UNINITIALIZED_STATE: {
+     123           0 :         ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is not possible from any state", getPrintName().c_str(), getStateAsString(UNINITIALIZED_STATE).c_str());
+     124           0 :         return false;
+     125             :         break;
+     126             :       }
+     127             : 
+     128           7 :       case INITIALIZED_STATE: {
+     129           7 :         if (current_state_ != UNINITIALIZED_STATE) {
+     130           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s", getPrintName().c_str(), getStateAsString(INITIALIZED_STATE).c_str(),
+     131             :                              getStateAsString(UNINITIALIZED_STATE).c_str());
+     132           0 :           return false;
+     133             :         }
+     134           7 :         break;
+     135             :       }
+     136             : 
+     137           7 :       case READY_FOR_TAKEOFF_STATE: {
+     138           7 :         if (current_state_ != INITIALIZED_STATE && current_state_ != LANDED_STATE) {
+     139           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s or %s", getPrintName().c_str(),
+     140             :                              getStateAsString(READY_FOR_TAKEOFF_STATE).c_str(), getStateAsString(INITIALIZED_STATE).c_str(),
+     141             :                              getStateAsString(LANDED_STATE).c_str());
+     142           0 :           return false;
+     143             :         }
+     144           7 :         break;
+     145             :       }
+     146             : 
+     147           5 :       case TAKING_OFF_STATE: {
+     148           5 :         if (current_state_ != READY_FOR_TAKEOFF_STATE) {
+     149           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s", getPrintName().c_str(), getStateAsString(TAKING_OFF_STATE).c_str(),
+     150             :                              getStateAsString(READY_FOR_TAKEOFF_STATE).c_str());
+     151           0 :           return false;
+     152             :         }
+     153           5 :         break;
+     154             :       }
+     155             : 
+     156           5 :       case FLYING_STATE: {
+     157           5 :         if (current_state_ != TAKING_OFF_STATE && current_state_ != HOVER_STATE && current_state_ != ESTIMATOR_SWITCHING_STATE) {
+     158           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s or %s or %s", getPrintName().c_str(), getStateAsString(FLYING_STATE).c_str(),
+     159             :                              getStateAsString(TAKING_OFF_STATE).c_str(), getStateAsString(HOVER_STATE).c_str(),
+     160             :                              getStateAsString(ESTIMATOR_SWITCHING_STATE).c_str());
+     161           0 :           return false;
+     162             :         }
+     163           5 :         break;
+     164             :       }
+     165             : 
+     166           0 :       case HOVER_STATE: {
+     167           0 :         if (current_state_ != FLYING_STATE) {
+     168           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s", getPrintName().c_str(), getStateAsString(HOVER_STATE).c_str(),
+     169             :                              getStateAsString(FLYING_STATE).c_str());
+     170           0 :           return false;
+     171             :         }
+     172           0 :         break;
+     173             :       }
+     174             : 
+     175           0 :       case ESTIMATOR_SWITCHING_STATE: {
+     176           0 :         if (current_state_ != FLYING_STATE && current_state_ != HOVER_STATE) {
+     177           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s or %s", getPrintName().c_str(),
+     178             :                              getStateAsString(ESTIMATOR_SWITCHING_STATE).c_str(), getStateAsString(FLYING_STATE).c_str(),
+     179             :                              getStateAsString(HOVER_STATE).c_str());
+     180           0 :           return false;
+     181             :         }
+     182           0 :         pre_switch_state_ = current_state_;
+     183           0 :         break;
+     184             :       }
+     185             : 
+     186           0 :       case LANDING_STATE: {
+     187           0 :         if (current_state_ != FLYING_STATE && current_state_ != HOVER_STATE) {
+     188           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s or %s", getPrintName().c_str(), getStateAsString(LANDING_STATE).c_str(),
+     189             :                              getStateAsString(FLYING_STATE).c_str(), getStateAsString(HOVER_STATE).c_str());
+     190           0 :           return false;
+     191             :         }
+     192           0 :         break;
+     193             :       }
+     194             : 
+     195           0 :       case LANDED_STATE: {
+     196           0 :         if (current_state_ != LANDING_STATE) {
+     197           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s", getPrintName().c_str(), getStateAsString(LANDED_STATE).c_str(),
+     198             :                              getStateAsString(LANDING_STATE).c_str());
+     199           0 :           return false;
+     200             :         }
+     201           0 :         break;
+     202             :       }
+     203             : 
+     204           0 :       case DUMMY_STATE: {
+     205           0 :         if (current_state_ != INITIALIZED_STATE) {
+     206           0 :           ROS_ERROR_THROTTLE(1.0, "[%s]: transition to %s is possible only from %s", getPrintName().c_str(), getStateAsString(DUMMY_STATE).c_str(),
+     207             :                              getStateAsString(INITIALIZED_STATE).c_str());
+     208           0 :           return false;
+     209             :         }
+     210           0 :         break;
+     211             :       }
+     212           0 :       case EMERGENCY_STATE: {
+     213           0 :         ROS_WARN("[%s]: transition to %s", getPrintName().c_str(), getStateAsString(EMERGENCY_STATE).c_str());
+     214           0 :         break;
+     215             :       }
+     216             : 
+     217           0 :       case ERROR_STATE: {
+     218           0 :         ROS_WARN("[%s]: transition to %s", getPrintName().c_str(), getStateAsString(ERROR_STATE).c_str());
+     219           0 :         break;
+     220             :       }
+     221             : 
+     222           0 :       case FAILSAFE_STATE: {
+     223           0 :         ROS_WARN("[%s]: transition to %s", getPrintName().c_str(), getStateAsString(FAILSAFE_STATE).c_str());
+     224           0 :         break;
+     225             :       }
+     226             : 
+     227           0 :       default: {
+     228           0 :         ROS_ERROR_THROTTLE(1.0, "[%s]: rejected transition to unknown state id %d", getPrintName().c_str(), target_state);
+     229           0 :         return false;
+     230             :         break;
+     231             :       }
+     232             :     }
+     233             : 
+     234          24 :     std::scoped_lock lock(mtx_state_);
+     235             :     {
+     236          24 :       previous_state_ = current_state_;
+     237          24 :       current_state_  = target_state;
+     238             :     }
+     239             : 
+     240          24 :     ROS_INFO("[%s]: successfully changed states %s -> %s", getPrintName().c_str(), getStateAsString(previous_state_).c_str(),
+     241             :              getStateAsString(current_state_).c_str());
+     242             : 
+     243          24 :     return true;
+     244             :   }
+     245             :   /*//}*/
+     246             : 
+     247             :   /*//{ changeToPreSwitchState() */
+     248           0 :   void changeToPreSwitchState() {
+     249           0 :     changeState(pre_switch_state_);
+     250           0 :   }
+     251             :   /*//}*/
+     252             : 
+     253             : private:
+     254             :   const std::string name_ = "StateMachine";
+     255             :   const std::string nodelet_name_;
+     256             : 
+     257             :   SMState_t current_state_    = UNINITIALIZED_STATE;
+     258             :   SMState_t previous_state_   = UNINITIALIZED_STATE;
+     259             :   SMState_t pre_switch_state_ = UNINITIALIZED_STATE;
+     260             : 
+     261             :   mutable std::mutex mtx_state_;
+     262             : 
+     263             :   std::string getName() const {
+     264             :     return name_;
+     265             :   }
+     266             : 
+     267          24 :   std::string getPrintName() const {
+     268          48 :     return nodelet_name_ + "/" + name_;
+     269             :   }
+     270             : 
+     271             :   // clang-format off
+     272             :   const std::vector<std::string> sm_state_names_ = {
+     273             :   "UNINITIALIZED_STATE",
+     274             :   "INITIALIZED_STATE",
+     275             :   "READY_FOR_TAKEOFF_STATE",
+     276             :   "TAKING_OFF_STATE",
+     277             :   "FLYING_STATE",
+     278             :   "HOVER_STATE",
+     279             :   "LANDING_STATE",
+     280             :   "LANDED_STATE",
+     281             :   "ESTIMATOR_SWITCHING_STATE",
+     282             :   "DUMMY_STATE",
+     283             :   "EMERGENCY_STATE",
+     284             :   "FAILSAFE_STATE",
+     285             :   "ERROR_STATE"
+     286             :   };
+     287             :   // clang-format on
+     288             : };
+     289             : /*//}*/
+     290             : 
+     291             : /*//{ class EstimationManager */
+     292             : class EstimationManager : public nodelet::Nodelet {
+     293             : 
+     294             : private:
+     295             :   const std::string nodelet_name_ = "EstimationManager";
+     296             :   const std::string package_name_ = "mrs_uav_managers";
+     297             : 
+     298             :   ros::NodeHandle nh_;
+     299             : 
+     300             :   std::string _custom_config_;
+     301             :   std::string _platform_config_;
+     302             :   std::string _world_config_;
+     303             : 
+     304             :   std::shared_ptr<CommonHandlers_t> ch_;
+     305             : 
+     306             :   std::shared_ptr<StateMachine> sm_;
+     307             : 
+     308             :   mrs_lib::SubscribeHandler<mrs_msgs::ControlManagerDiagnostics> sh_control_manager_diag_;
+     309             :   mrs_lib::SubscribeHandler<mrs_msgs::EstimatorInput>            sh_control_input_;
+     310             : 
+     311             :   mrs_lib::PublisherHandler<mrs_msgs::EstimationDiagnostics> ph_diagnostics_;
+     312             :   mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>        ph_max_flight_z_;
+     313             :   mrs_lib::PublisherHandler<mrs_msgs::UavState>              ph_uav_state_;
+     314             :   mrs_lib::PublisherHandler<nav_msgs::Odometry>              ph_odom_main_;
+     315             :   mrs_lib::PublisherHandler<nav_msgs::Odometry>              ph_odom_slow_;  // use topic throttler instead?
+     316             :   mrs_lib::PublisherHandler<nav_msgs::Odometry>              ph_innovation_;
+     317             : 
+     318             :   mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped> ph_altitude_amsl_;
+     319             :   mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped> ph_altitude_agl_;
+     320             : 
+     321             :   mrs_lib::PublisherHandler<geometry_msgs::QuaternionStamped> ph_orientation_;
+     322             : 
+     323             :   ros::Timer timer_publish_;
+     324             :   void       timerPublish(const ros::TimerEvent& event);
+     325             : 
+     326             :   ros::Timer timer_publish_diagnostics_;
+     327             :   void       timerPublishDiagnostics(const ros::TimerEvent& event);
+     328             : 
+     329             :   ros::Timer timer_check_health_;
+     330             :   void       timerCheckHealth(const ros::TimerEvent& event);
+     331             : 
+     332             :   ros::Timer timer_initialization_;
+     333             :   void       timerInitialization(const ros::TimerEvent& event);
+     334             : 
+     335             :   ros::ServiceServer srvs_change_estimator_;
+     336             :   bool               callbackChangeEstimator(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res);
+     337             :   int                estimator_switch_count_ = 0;
+     338             : 
+     339             : 
+     340             :   ros::ServiceServer srvs_toggle_callbacks_;
+     341             :   bool               callbackToggleServiceCallbacks(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res);
+     342             :   bool               callbacks_enabled_             = false;
+     343             :   bool               callbacks_disabled_by_service_ = false;
+     344             : 
+     345             :   bool                                             callFailsafeService();
+     346             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger> srvch_failsafe_;
+     347             :   bool                                             failsafe_call_succeeded_ = false;
+     348             : 
+     349             :   // TODO service clients
+     350             :   /* mrs_lib::ServiceClientHandler<std_srvs::Trigger> srvc_hover_; */
+     351             :   /* mrs_lib::ServiceClientHandler<mrs_msgs::ReferenceStampedSrv> srvc_reference_; */
+     352             :   /* mrs_lib::ServiceClientHandler<std_srvs::Trigger> srvc_ehover_; */
+     353             :   /* mrs_lib::ServiceClientHandler<std_srvs::SetBool> srvc_enable_callbacks_; */
+     354             : 
+     355             :   // | ------------- dynamic loading of estimators ------------- |
+     356             :   std::unique_ptr<pluginlib::ClassLoader<mrs_uav_managers::StateEstimator>> state_estimator_loader_;  // pluginlib loader of dynamically loaded estimators
+     357             :   std::vector<std::string>                                                  estimator_names_;         // list of estimator names
+     358             :   std::vector<boost::shared_ptr<mrs_uav_managers::StateEstimator>>          estimator_list_;          // list of estimators
+     359             :   std::mutex                                                                mutex_estimator_list_;
+     360             :   std::vector<std::string>                                                  switchable_estimator_names_;
+     361             :   std::mutex                                                                mutex_switchable_estimator_names_;
+     362             :   std::string                                                               initial_estimator_name_ = "UNDEFINED_INITIAL_ESTIMATOR";
+     363             :   boost::shared_ptr<mrs_uav_managers::StateEstimator>                       initial_estimator_;
+     364             :   boost::shared_ptr<mrs_uav_managers::StateEstimator>                       active_estimator_;
+     365             :   std::mutex                                                                mutex_active_estimator_;
+     366             : 
+     367             :   std::unique_ptr<pluginlib::ClassLoader<mrs_uav_managers::AglEstimator>> agl_estimator_loader_;  // pluginlib loader of dynamically loaded estimators
+     368             :   std::string                                                             est_alt_agl_name_ = "UNDEFINED_AGL_ESTIMATOR";
+     369             :   boost::shared_ptr<mrs_uav_managers::AglEstimator>                       est_alt_agl_;
+     370             :   bool                                                                    is_using_agl_estimator_;
+     371             : 
+     372             :   double max_flight_z_;
+     373             : 
+     374             :   bool switchToHealthyEstimator();
+     375             :   void switchToEstimator(const boost::shared_ptr<mrs_uav_managers::StateEstimator>& target_estimator);
+     376             : 
+     377             :   bool loadConfigFile(const std::string& file_path);
+     378             : 
+     379             : public:
+     380           7 :   EstimationManager() {
+     381           7 :   }
+     382             : 
+     383             :   void onInit();
+     384             : 
+     385             :   std::string getName() const;
+     386             : };
+     387             : /*//}*/
+     388             : 
+     389             : /*//{ onInit() */
+     390           7 : void EstimationManager::onInit() {
+     391             : 
+     392           7 :   nh_ = nodelet::Nodelet::getMTPrivateNodeHandle();
+     393             : 
+     394           7 :   ros::Time::waitForValid();
+     395             : 
+     396           7 :   ROS_INFO("[%s]: initializing", getName().c_str());
+     397             : 
+     398           7 :   sm_ = std::make_shared<StateMachine>(nodelet_name_);
+     399             : 
+     400           7 :   ch_ = std::make_shared<CommonHandlers_t>();
+     401             : 
+     402           7 :   ch_->nodelet_name = nodelet_name_;
+     403           7 :   ch_->package_name = package_name_;
+     404             : 
+     405             :   // finish initialization in a oneshot timer, so that we don't block loading of other nodelets by the nodelet manager
+     406           7 :   timer_initialization_ = nh_.createTimer(ros::Rate(1.0), &EstimationManager::timerInitialization, this, true, true);
+     407           7 : }
+     408             : /*//}*/
+     409             : 
+     410             : // --------------------------------------------------------------
+     411             : // |                          callbacks                         |
+     412             : // --------------------------------------------------------------
+     413             : 
+     414             : // | --------------------- timer callbacks -------------------- |
+     415             : 
+     416             : /*//{ timerPublish() */
+     417        9816 : void EstimationManager::timerPublish([[maybe_unused]] const ros::TimerEvent& event) {
+     418             : 
+     419        9816 :   if (!sm_->isInitialized()) {
+     420         870 :     return;
+     421             :   }
+     422             : 
+     423       19632 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("EstimationManager::timerPublish", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     424             : 
+     425        9816 :   if (sm_->isInState(StateMachine::ESTIMATOR_SWITCHING_STATE)) {
+     426           0 :     ROS_WARN("[%s]: Not publishing during estimator switching.", getName().c_str());
+     427           0 :     return;
+     428             :   }
+     429             : 
+     430        9816 :   if (!sm_->isInPublishableState()) {
+     431         870 :     ROS_WARN_THROTTLE(1.0, "[%s]: not publishing uav state in %s", getName().c_str(), sm_->getCurrentStateString().c_str());
+     432         870 :     return;
+     433             :   }
+     434             : 
+     435        8946 :   mrs_msgs::UavState uav_state;
+     436        8946 :   auto               ret = active_estimator_->getUavState();
+     437        8946 :   if (ret) {
+     438        8946 :     uav_state = ret.value();
+     439             :   } else {
+     440           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: Active estimator did not provide uav_state.", getName().c_str());
+     441           0 :     return;
+     442             :   }
+     443             : 
+     444        8946 :   if (!Support::noNans(uav_state.pose.orientation)) {
+     445           0 :     ROS_ERROR("[%s]: nan in uav state orientation", getName().c_str());
+     446           0 :     return;
+     447             :   }
+     448             : 
+     449             : 
+     450        8946 :   if (active_estimator_->isMitigatingJump()) {
+     451           0 :     estimator_switch_count_++;
+     452             :   }
+     453        8946 :   uav_state.estimator_iteration = estimator_switch_count_;
+     454             : 
+     455        8946 :   scope_timer.checkpoint("get uav state");
+     456             :   // TODO state health checks
+     457             : 
+     458        8946 :   ph_uav_state_.publish(uav_state);
+     459             : 
+     460        8946 :   scope_timer.checkpoint("pub uav state");
+     461       17892 :   nav_msgs::Odometry odom_main = Support::uavStateToOdom(uav_state);
+     462             : 
+     463        8946 :   scope_timer.checkpoint("uav state to odom");
+     464       17892 :   const std::vector<double> pose_covariance = active_estimator_->getPoseCovariance();
+     465      331002 :   for (size_t i = 0; i < pose_covariance.size(); i++) {
+     466      322056 :     odom_main.pose.covariance[i] = pose_covariance[i];
+     467             :   }
+     468             : 
+     469       17892 :   const std::vector<double> twist_covariance = active_estimator_->getTwistCovariance();
+     470      331002 :   for (size_t i = 0; i < twist_covariance.size(); i++) {
+     471      322056 :     odom_main.twist.covariance[i] = twist_covariance[i];
+     472             :   }
+     473             : 
+     474        8946 :   scope_timer.checkpoint("get covariance");
+     475        8946 :   ph_odom_main_.publish(odom_main);
+     476             : 
+     477       17892 :   nav_msgs::Odometry innovation = active_estimator_->getInnovation();
+     478        8946 :   ph_innovation_.publish(innovation);
+     479             : 
+     480             : 
+     481       17892 :   mrs_msgs::Float64Stamped agl_height;
+     482             : 
+     483        8946 :   if (is_using_agl_estimator_) {
+     484        4787 :     agl_height = est_alt_agl_->getUavAglHeight();
+     485        4787 :     ph_altitude_agl_.publish(agl_height);
+     486             :   }
+     487             : }
+     488             : /*//}*/
+     489             : 
+     490             : /*//{ timerPublishDiagnostics() */
+     491         978 : void EstimationManager::timerPublishDiagnostics([[maybe_unused]] const ros::TimerEvent& event) {
+     492             : 
+     493         978 :   if (!sm_->isInitialized()) {
+     494          82 :     return;
+     495             :   }
+     496             : 
+     497        1956 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("EstimationManager::timerPublishDiagnostics", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     498             : 
+     499         978 :   if (sm_->isInState(StateMachine::ESTIMATOR_SWITCHING_STATE)) {
+     500           0 :     ROS_WARN("[%s]: Not publishing diagnostics during estimator switching.", getName().c_str());
+     501           0 :     return;
+     502             :   }
+     503             : 
+     504         978 :   if (!sm_->isInPublishableState()) {
+     505          82 :     ROS_WARN_THROTTLE(1.0, "[%s]: not publishing uav state in %s", getName().c_str(), sm_->getCurrentStateString().c_str());
+     506          82 :     return;
+     507             :   }
+     508             : 
+     509         896 :   mrs_msgs::UavState uav_state;
+     510         896 :   auto               ret = active_estimator_->getUavState();
+     511         896 :   if (ret) {
+     512         896 :     uav_state = ret.value();
+     513             :   } else {
+     514           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: Active estimator did not provide uav_state.", getName().c_str());
+     515           0 :     return;
+     516             :   }
+     517             : 
+     518         896 :   if (!Support::noNans(uav_state.pose.orientation)) {
+     519           0 :     ROS_ERROR("[%s]: nan in uav state orientation", getName().c_str());
+     520           0 :     return;
+     521             :   }
+     522             : 
+     523        1792 :   mrs_msgs::Float64Stamped agl_height;
+     524             : 
+     525         896 :   if (is_using_agl_estimator_) {
+     526         480 :     agl_height = est_alt_agl_->getUavAglHeight();
+     527         480 :     ph_altitude_agl_.publish(agl_height);
+     528             :   }
+     529             : 
+     530        1792 :   mrs_msgs::Float64Stamped max_flight_z_msg;
+     531         896 :   max_flight_z_msg.header.stamp = ros::Time::now();
+     532         896 :   if (active_estimator_ && active_estimator_->isInitialized()) {
+     533         896 :     max_flight_z_msg.header.frame_id = active_estimator_->getFrameId();
+     534         896 :     max_flight_z_msg.value           = active_estimator_->getMaxFlightZ();
+     535             :   }
+     536         896 :   max_flight_z_ = max_flight_z_msg.value;
+     537         896 :   ph_max_flight_z_.publish(max_flight_z_msg);
+     538             : 
+     539             :   // publish diagnostics
+     540        1792 :   mrs_msgs::EstimationDiagnostics diagnostics;
+     541             : 
+     542         896 :   diagnostics.header.stamp   = uav_state.header.stamp;
+     543         896 :   diagnostics.child_frame_id = uav_state.child_frame_id;
+     544             : 
+     545         896 :   diagnostics.pose         = uav_state.pose;
+     546         896 :   diagnostics.velocity     = uav_state.velocity;
+     547         896 :   diagnostics.acceleration = uav_state.acceleration;
+     548             : 
+     549         896 :   diagnostics.sm_state                 = sm_->getCurrentStateString();
+     550         896 :   diagnostics.max_flight_z             = max_flight_z_msg.value;
+     551         896 :   diagnostics.estimator_iteration      = estimator_switch_count_;
+     552         896 :   diagnostics.estimation_rate          = ch_->desired_uav_state_rate;
+     553         896 :   diagnostics.running_state_estimators = estimator_names_;
+     554             : 
+     555             :   {
+     556        1792 :     std::scoped_lock lock(mutex_switchable_estimator_names_);
+     557         896 :     diagnostics.switchable_state_estimators = switchable_estimator_names_;
+     558             :   }
+     559             : 
+     560             : 
+     561         896 :   if (active_estimator_ && active_estimator_->isInitialized()) {
+     562         896 :     diagnostics.header.frame_id         = active_estimator_->getFrameId();
+     563         896 :     diagnostics.current_state_estimator = active_estimator_->getName();
+     564             :   } else {
+     565           0 :     diagnostics.header.frame_id         = "";
+     566           0 :     diagnostics.current_state_estimator = "";
+     567             :   }
+     568             : 
+     569         896 :   diagnostics.estimator_horizontal = uav_state.estimator_horizontal;
+     570         896 :   diagnostics.estimator_vertical   = uav_state.estimator_vertical;
+     571         896 :   diagnostics.estimator_heading    = uav_state.estimator_heading;
+     572             : 
+     573         896 :   if (is_using_agl_estimator_) {
+     574         480 :     diagnostics.estimator_agl_height = est_alt_agl_name_;
+     575         480 :     diagnostics.agl_height           = agl_height.value;
+     576             :   } else {
+     577         416 :     diagnostics.estimator_agl_height = "NOT_USED";
+     578         416 :     diagnostics.agl_height           = std::nanf("");
+     579             :   }
+     580             : 
+     581         896 :   diagnostics.platform_config = _platform_config_;
+     582         896 :   diagnostics.custom_config   = _custom_config_;
+     583             : 
+     584         896 :   ph_diagnostics_.publish(diagnostics);
+     585             : 
+     586         896 :   ROS_INFO_THROTTLE(5.0, "[%s]: %s. pos: [%.2f, %.2f, %.2f] m. Estimator: %s. Max. z.: %.2f m. Estimator switches: %d.", getName().c_str(),
+     587             :                     sm_->getCurrentStateString().c_str(), uav_state.pose.position.x, uav_state.pose.position.y, uav_state.pose.position.z,
+     588             :                     active_estimator_->getName().c_str(), max_flight_z_, estimator_switch_count_);
+     589             : }
+     590             : /*//}*/
+     591             : 
+     592             : /*//{ timerCheckHealth() */
+     593        9816 : void EstimationManager::timerCheckHealth([[maybe_unused]] const ros::TimerEvent& event) {
+     594             : 
+     595        9816 :   if (!sm_->isInitialized()) {
+     596           0 :     return;
+     597             :   }
+     598             : 
+     599       29448 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("EstimationManager::timerCheckHealth", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     600             : 
+     601             :   /*//{ start ready estimators, check switchable estimators */
+     602       19632 :   std::vector<std::string> switchable_estimator_names;
+     603       19632 :   for (auto estimator : estimator_list_) {
+     604             : 
+     605        9816 :     if (estimator->isReady()) {
+     606             :       try {
+     607           9 :         ROS_INFO_THROTTLE(1.0, "[%s]: starting the estimator '%s'", getName().c_str(), estimator->getName().c_str());
+     608           9 :         estimator->start();
+     609             :       }
+     610           0 :       catch (std::runtime_error& ex) {
+     611           0 :         ROS_ERROR("[%s]: exception caught during estimator starting: '%s'", getName().c_str(), ex.what());
+     612           0 :         ros::shutdown();
+     613             :       }
+     614             :     }
+     615             : 
+     616        9816 :     if (estimator->isRunning() && estimator->getName() != "dummy" && estimator->getName() != "ground_truth") {
+     617        9675 :       switchable_estimator_names.push_back(estimator->getName());
+     618             :     }
+     619             :   }
+     620             : 
+     621             :   {
+     622       19632 :     std::scoped_lock lock(mutex_switchable_estimator_names_);
+     623        9816 :     switchable_estimator_names_ = switchable_estimator_names;
+     624             :   }
+     625             : 
+     626        9816 :   if (is_using_agl_estimator_ && est_alt_agl_->isReady()) {
+     627           4 :     est_alt_agl_->start();
+     628             :   }
+     629             : 
+     630             :   /*//}*/
+     631             : 
+     632       14331 :   if (!callbacks_disabled_by_service_ &&
+     633       14331 :       (sm_->isInState(StateMachine::FLYING_STATE) || sm_->isInState(StateMachine::HOVER_STATE) || sm_->isInState(StateMachine::READY_FOR_TAKEOFF_STATE))) {
+     634        3635 :     callbacks_enabled_ = true;
+     635             :   } else {
+     636        6181 :     callbacks_enabled_ = false;
+     637             :   }
+     638             : 
+     639             :   // TODO fuj if, zmenit na switch
+     640             :   // activate initial estimator
+     641        9816 :   if (sm_->isInState(StateMachine::INITIALIZED_STATE) && initial_estimator_->isRunning()) {
+     642        1460 :     std::scoped_lock lock(mutex_active_estimator_);
+     643         730 :     ROS_INFO_THROTTLE(1.0, "[%s]: activating the initial estimator %s", getName().c_str(), initial_estimator_->getName().c_str());
+     644         730 :     active_estimator_ = initial_estimator_;
+     645         730 :     if (active_estimator_->getName() == "dummy") {
+     646           0 :       sm_->changeState(StateMachine::DUMMY_STATE);
+     647             :     } else {
+     648         730 :       if (!is_using_agl_estimator_ || est_alt_agl_->isRunning()) {
+     649           7 :         sm_->changeState(StateMachine::READY_FOR_TAKEOFF_STATE);
+     650             :       } else {
+     651         723 :         ROS_INFO_THROTTLE(1.0, "[%s]: %s agl estimator: %s to be running", getName().c_str(), Support::waiting_for_string.c_str(),
+     652             :                           est_alt_agl_->getName().c_str());
+     653             :       }
+     654             :     }
+     655             :   }
+     656             : 
+     657             :   // active estimator is in faulty state, we need to switch to healthy estimator
+     658        9816 :   if (sm_->isInTheAir() && active_estimator_->isError()) {
+     659           0 :     sm_->changeState(StateMachine::ESTIMATOR_SWITCHING_STATE);
+     660             :   }
+     661             : 
+     662        9816 :   if (sm_->isInState(StateMachine::ESTIMATOR_SWITCHING_STATE)) {
+     663           0 :     if (switchToHealthyEstimator()) {
+     664           0 :       sm_->changeToPreSwitchState();
+     665             :     } else {  // cannot switch to healthy estimator - failsafe necessary
+     666           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Cannot switch to any healthy estimator. Triggering failsafe.", getName().c_str());
+     667           0 :       sm_->changeState(StateMachine::FAILSAFE_STATE);
+     668             :     }
+     669             :   }
+     670             : 
+     671        9816 :   if (sm_->isInState(StateMachine::FAILSAFE_STATE)) {
+     672           0 :     if (!failsafe_call_succeeded_ && callFailsafeService()) {
+     673           0 :       ROS_INFO_THROTTLE(1.0, "[%s]: failsafe called successfully", getName().c_str());
+     674           0 :       failsafe_call_succeeded_ = true;
+     675             :     }
+     676           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: we are in failsafe state", getName().c_str());
+     677             :   }
+     678             : 
+     679        9816 :   if (sm_->isInState(StateMachine::READY_FOR_TAKEOFF_STATE)) {
+     680        5100 :     if (sh_control_manager_diag_.hasMsg() && sh_control_manager_diag_.getMsg()->active_tracker == "LandoffTracker") {
+     681           5 :       sm_->changeState(StateMachine::TAKING_OFF_STATE);
+     682             :     }
+     683             :   }
+     684             : 
+     685        9816 :   if (sm_->isInState(StateMachine::TAKING_OFF_STATE)) {
+     686        3706 :     if (sh_control_manager_diag_.hasMsg() && sh_control_manager_diag_.getMsg()->active_tracker != "LandoffTracker") {
+     687           5 :       sm_->changeState(StateMachine::FLYING_STATE);
+     688             :     }
+     689             :   }
+     690             : 
+     691        9816 :   if (sm_->isInState(StateMachine::FLYING_STATE)) {
+     692         156 :     if ((ros::Time::now() - sh_control_input_.lastMsgTime()).toSec() > 0.1) {
+     693         120 :       ROS_WARN_THROTTLE(1.0, "[%s]: not received control input for %.4fs, estimation suboptimal, potentially unstable", getName().c_str(),
+     694             :                         (ros::Time::now() - sh_control_input_.lastMsgTime()).toSec());
+     695             :     }
+     696             :   }
+     697             : }
+     698             : /*//}*/
+     699             : 
+     700             : /*//{ timerInitialization() */
+     701           7 : void EstimationManager::timerInitialization([[maybe_unused]] const ros::TimerEvent& event) {
+     702             : 
+     703          14 :   mrs_lib::ParamLoader param_loader(nh_, getName());
+     704             : 
+     705           7 :   param_loader.loadParam("custom_config", _custom_config_);
+     706           7 :   param_loader.loadParam("platform_config", _platform_config_);
+     707           7 :   param_loader.loadParam("world_config", _world_config_);
+     708             : 
+     709           7 :   if (_custom_config_ != "") {
+     710           7 :     param_loader.addYamlFile(_custom_config_);
+     711             :   }
+     712             : 
+     713           7 :   if (_platform_config_ != "") {
+     714           7 :     param_loader.addYamlFile(_platform_config_);
+     715             :   }
+     716             : 
+     717           7 :   if (_world_config_ != "") {
+     718           7 :     param_loader.addYamlFile(_world_config_);
+     719             :   }
+     720             : 
+     721           7 :   param_loader.addYamlFileFromParam("private_config");
+     722           7 :   param_loader.addYamlFileFromParam("public_config");
+     723           7 :   param_loader.addYamlFileFromParam("estimators_config");
+     724           7 :   param_loader.addYamlFileFromParam("active_estimators_config");
+     725             : 
+     726           7 :   param_loader.loadParam("uav_name", ch_->uav_name);
+     727             : 
+     728             :   /*//{ load world_origin parameters */
+     729             : 
+     730          14 :   std::string world_origin_units;
+     731           7 :   bool        is_origin_param_ok = true;
+     732           7 :   double      world_origin_x     = 0;
+     733           7 :   double      world_origin_y     = 0;
+     734             : 
+     735           7 :   param_loader.loadParam("world_origin/units", world_origin_units);
+     736             : 
+     737           7 :   if (Support::toLowercase(world_origin_units) == "utm") {
+     738           0 :     ROS_INFO("[%s]: Loading world origin in UTM units.", getName().c_str());
+     739           0 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_x", world_origin_x);
+     740           0 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_y", world_origin_y);
+     741             : 
+     742           7 :   } else if (Support::toLowercase(world_origin_units) == "latlon") {
+     743             :     double lat, lon;
+     744           7 :     ROS_INFO("[%s]: Loading world origin in LatLon units.", getName().c_str());
+     745           7 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_x", lat);
+     746           7 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_y", lon);
+     747           7 :     mrs_lib::UTM(lat, lon, &world_origin_x, &world_origin_y);
+     748           7 :     ROS_INFO("[%s]: Converted to UTM x: %f, y: %f.", getName().c_str(), world_origin_x, world_origin_y);
+     749             : 
+     750             :   } else {
+     751           0 :     ROS_ERROR("[%s]: world_origin_units must be (\"UTM\"|\"LATLON\"). Got '%s'", getName().c_str(), world_origin_units.c_str());
+     752           0 :     ros::shutdown();
+     753             :   }
+     754             : 
+     755           7 :   ch_->world_origin.x = world_origin_x;
+     756           7 :   ch_->world_origin.y = world_origin_y;
+     757             : 
+     758           7 :   if (!is_origin_param_ok) {
+     759           0 :     ROS_ERROR("[%s]: Could not load all mandatory parameters from world file. Please check your world file.", getName().c_str());
+     760           0 :     ros::shutdown();
+     761             :   }
+     762             :   /*//}*/
+     763             : 
+     764           7 :   param_loader.setPrefix(ch_->package_name + "/" + Support::toSnakeCase(ch_->nodelet_name) + "/");
+     765             : 
+     766             :   /*//{ load parameters into common handlers */
+     767           7 :   param_loader.loadParam("frame_id/fcu", ch_->frames.fcu);
+     768           7 :   ch_->frames.ns_fcu = ch_->uav_name + "/" + ch_->frames.fcu;
+     769             : 
+     770           7 :   param_loader.loadParam("frame_id/fcu_untilted", ch_->frames.fcu_untilted);
+     771           7 :   ch_->frames.ns_fcu_untilted = ch_->uav_name + "/" + ch_->frames.fcu_untilted;
+     772             : 
+     773           7 :   param_loader.loadParam("frame_id/rtk_antenna", ch_->frames.rtk_antenna);
+     774           7 :   ch_->frames.ns_rtk_antenna = ch_->uav_name + "/" + ch_->frames.rtk_antenna;
+     775             : 
+     776           7 :   ch_->transformer = std::make_shared<mrs_lib::Transformer>(nh_, getName());
+     777           7 :   ch_->transformer->retryLookupNewest(true);
+     778             : 
+     779           7 :   param_loader.loadParam("rate/diagnostics", ch_->desired_diagnostics_rate);
+     780             : 
+     781             :   /*//}*/
+     782             : 
+     783             :   /*//{ load parameters */
+     784             : 
+     785             :   /*//{ publish debug topics parameters */
+     786           7 :   param_loader.loadParam("debug_topics/input", ch_->debug_topics.input);
+     787           7 :   param_loader.loadParam("debug_topics/output", ch_->debug_topics.output);
+     788           7 :   param_loader.loadParam("debug_topics/state", ch_->debug_topics.state);
+     789           7 :   param_loader.loadParam("debug_topics/covariance", ch_->debug_topics.covariance);
+     790           7 :   param_loader.loadParam("debug_topics/innovation", ch_->debug_topics.innovation);
+     791           7 :   param_loader.loadParam("debug_topics/diagnostics", ch_->debug_topics.diag);
+     792           7 :   param_loader.loadParam("debug_topics/correction", ch_->debug_topics.correction);
+     793           7 :   param_loader.loadParam("debug_topics/correction_delay", ch_->debug_topics.corr_delay);
+     794             :   /*//}*/
+     795             : 
+     796             :   /*//}*/
+     797             : 
+     798          14 :   mrs_lib::SubscribeHandlerOptions shopts;
+     799           7 :   shopts.nh                 = nh_;
+     800           7 :   shopts.node_name          = getName();
+     801           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+     802           7 :   shopts.threadsafe         = true;
+     803           7 :   shopts.autostart          = true;
+     804           7 :   shopts.queue_size         = 10;
+     805           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     806             : 
+     807             :   /*//{ wait for hw api message */
+     808             : 
+     809             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiCapabilities> sh_hw_api_capabilities_ =
+     810          21 :       mrs_lib::SubscribeHandler<mrs_msgs::HwApiCapabilities>(shopts, "hw_api_capabilities_in");
+     811          14 :   while (!sh_hw_api_capabilities_.hasMsg()) {
+     812           7 :     ROS_INFO("[%s]: %s hw_api_capabilities message at topic: %s", getName().c_str(), Support::waiting_for_string.c_str(),
+     813             :              sh_hw_api_capabilities_.topicName().c_str());
+     814           7 :     ros::Duration(1.0).sleep();
+     815             :   }
+     816             : 
+     817          14 :   mrs_msgs::HwApiCapabilitiesConstPtr hw_api_capabilities = sh_hw_api_capabilities_.getMsg();
+     818             :   /*//}*/
+     819             : 
+     820             :   /*//{ wait for desired uav_state rate */
+     821           7 :   sh_control_manager_diag_ = mrs_lib::SubscribeHandler<mrs_msgs::ControlManagerDiagnostics>(shopts, "control_manager_diagnostics_in");
+     822          14 :   while (!sh_control_manager_diag_.hasMsg()) {
+     823           7 :     ROS_INFO("[%s]: %s control_manager_diagnostics message at topic: %s", getName().c_str(), Support::waiting_for_string.c_str(),
+     824             :              sh_control_manager_diag_.topicName().c_str());
+     825           7 :     ros::Duration(1.0).sleep();
+     826             :   }
+     827             : 
+     828          14 :   mrs_msgs::ControlManagerDiagnosticsConstPtr control_manager_diag_msg = sh_control_manager_diag_.getMsg();
+     829           7 :   ch_->desired_uav_state_rate                                          = control_manager_diag_msg->desired_uav_state_rate;
+     830           7 :   ROS_INFO("[%s]: The estimation is running at: %.2f Hz", getName().c_str(), ch_->desired_uav_state_rate);
+     831             :   /*//}*/
+     832             : 
+     833             :   /*//{ initialize subscribers */
+     834             : 
+     835           7 :   sh_control_input_ = mrs_lib::SubscribeHandler<mrs_msgs::EstimatorInput>(shopts, "control_input_in");
+     836             : 
+     837             :   /*//}*/
+     838             : 
+     839             :   /*//{ load state estimator plugins */
+     840           7 :   param_loader.loadParam("state_estimators", estimator_names_);
+     841             : 
+     842           7 :   state_estimator_loader_ = std::make_unique<pluginlib::ClassLoader<mrs_uav_managers::StateEstimator>>("mrs_uav_managers", "mrs_uav_managers::StateEstimator");
+     843             : 
+     844          14 :   for (size_t i = 0; i < estimator_names_.size(); i++) {
+     845             : 
+     846          14 :     const std::string estimator_name = estimator_names_[i];
+     847             : 
+     848             :     // load the estimator parameters
+     849          14 :     std::string address;
+     850           7 :     param_loader.loadParam(estimator_name + "/address", address);
+     851             : 
+     852             :     try {
+     853           7 :       ROS_INFO("[%s]: loading the estimator '%s'", getName().c_str(), address.c_str());
+     854           7 :       estimator_list_.push_back(state_estimator_loader_->createInstance(address.c_str()));
+     855             :     }
+     856           0 :     catch (pluginlib::CreateClassException& ex1) {
+     857           0 :       ROS_ERROR("[%s]: CreateClassException for the estimator '%s'", getName().c_str(), address.c_str());
+     858           0 :       ROS_ERROR("[%s]: Error: %s", getName().c_str(), ex1.what());
+     859           0 :       ros::shutdown();
+     860             :     }
+     861           0 :     catch (pluginlib::PluginlibException& ex) {
+     862           0 :       ROS_ERROR("[%s]: PluginlibException for the estimator '%s'", getName().c_str(), address.c_str());
+     863           0 :       ROS_ERROR("[%s]: Error: %s", getName().c_str(), ex.what());
+     864           0 :       ros::shutdown();
+     865             :     }
+     866             :   }
+     867             : 
+     868             :   /*//{ load agl estimator plugins */
+     869           7 :   param_loader.loadParam("agl_height_estimator", est_alt_agl_name_);
+     870           7 :   is_using_agl_estimator_ = est_alt_agl_name_ != "";
+     871           7 :   ROS_WARN_COND(!is_using_agl_estimator_, "[%s]: not using AGL estimator for min height safe checking", getName().c_str());
+     872             : 
+     873             : 
+     874           7 :   if (is_using_agl_estimator_) {
+     875             : 
+     876           4 :     agl_estimator_loader_ = std::make_unique<pluginlib::ClassLoader<mrs_uav_managers::AglEstimator>>("mrs_uav_managers", "mrs_uav_managers::AglEstimator");
+     877             : 
+     878             :     // load the estimator parameters
+     879           8 :     std::string address;
+     880           4 :     param_loader.loadParam(est_alt_agl_name_ + "/address", address);
+     881             : 
+     882             :     try {
+     883           4 :       ROS_INFO("[%s]: loading the estimator '%s'", getName().c_str(), address.c_str());
+     884           4 :       est_alt_agl_ = agl_estimator_loader_->createInstance(address.c_str());
+     885             :     }
+     886           0 :     catch (pluginlib::CreateClassException& ex1) {
+     887           0 :       ROS_ERROR("[%s]: CreateClassException for the estimator '%s'", getName().c_str(), address.c_str());
+     888           0 :       ROS_ERROR("[%s]: Error: %s", getName().c_str(), ex1.what());
+     889           0 :       ros::shutdown();
+     890             :     }
+     891           0 :     catch (pluginlib::PluginlibException& ex) {
+     892           0 :       ROS_ERROR("[%s]: PluginlibException for the estimator '%s'", getName().c_str(), address.c_str());
+     893           0 :       ROS_ERROR("[%s]: Error: %s", getName().c_str(), ex.what());
+     894           0 :       ros::shutdown();
+     895             :     }
+     896             :   }
+     897             :   /*//}*/
+     898             : 
+     899           7 :   ROS_INFO("[%s]: estimators were loaded", getName().c_str());
+     900             :   /*//}*/
+     901             : 
+     902             :   /*//{ check whether initial estimator was loaded */
+     903           7 :   param_loader.loadParam("initial_state_estimator", initial_estimator_name_);
+     904           7 :   bool initial_estimator_found = false;
+     905           7 :   for (auto estimator : estimator_list_) {
+     906           7 :     if (estimator->getName() == initial_estimator_name_) {
+     907           7 :       initial_estimator_      = estimator;
+     908           7 :       initial_estimator_found = true;
+     909           7 :       break;
+     910             :     }
+     911             :   }
+     912             : 
+     913           7 :   if (!initial_estimator_found) {
+     914           0 :     ROS_ERROR("[%s]: initial estimator %s could not be found among loaded estimators. shutting down", getName().c_str(), initial_estimator_name_.c_str());
+     915           0 :     ros::shutdown();
+     916             :   }
+     917             :   /*//}*/
+     918             : 
+     919             :   /*//{ initialize estimators */
+     920          14 :   for (auto estimator : estimator_list_) {
+     921             : 
+     922             :     // create private handlers
+     923          14 :     std::shared_ptr<mrs_uav_managers::estimation_manager::PrivateHandlers_t> ph = std::make_shared<mrs_uav_managers::estimation_manager::PrivateHandlers_t>();
+     924             : 
+     925           7 :     ph->loadConfigFile = boost::bind(&EstimationManager::loadConfigFile, this, _1);
+     926           7 :     ph->param_loader   = std::make_shared<mrs_lib::ParamLoader>(ros::NodeHandle(nh_, estimator->getName()), "EstimationManager/" + estimator->getName());
+     927             : 
+     928           7 :     if (_custom_config_ != "") {
+     929           7 :       ph->param_loader->addYamlFile(_custom_config_);
+     930             :     }
+     931             : 
+     932           7 :     if (_platform_config_ != "") {
+     933           7 :       ph->param_loader->addYamlFile(_platform_config_);
+     934             :     }
+     935             : 
+     936           7 :     if (_world_config_ != "") {
+     937           7 :       ph->param_loader->addYamlFile(_world_config_);
+     938             :     }
+     939             : 
+     940             :     try {
+     941           7 :       ROS_INFO("[%s]: initializing the estimator '%s'", getName().c_str(), estimator->getName().c_str());
+     942           7 :       estimator->initialize(nh_, ch_, ph);
+     943             :     }
+     944           0 :     catch (std::runtime_error& ex) {
+     945           0 :       ROS_ERROR("[%s]: exception caught during estimator initialization: '%s'", getName().c_str(), ex.what());
+     946           0 :       ros::shutdown();
+     947             :     }
+     948             : 
+     949           7 :     if (!estimator->isCompatibleWithHwApi(hw_api_capabilities)) {
+     950           0 :       ROS_ERROR("[%s]: estimator %s is not compatible with the hw api. Shutting down.", getName().c_str(), estimator->getName().c_str());
+     951           0 :       ros::shutdown();
+     952             :     }
+     953             :   }
+     954             : 
+     955             :   // | ----------- agl height estimator initialization ---------- |
+     956           7 :   if (is_using_agl_estimator_) {
+     957             : 
+     958           8 :     std::shared_ptr<mrs_uav_managers::estimation_manager::PrivateHandlers_t> ph = std::make_shared<mrs_uav_managers::estimation_manager::PrivateHandlers_t>();
+     959             : 
+     960           4 :     ph->loadConfigFile = boost::bind(&EstimationManager::loadConfigFile, this, _1);
+     961           4 :     ph->param_loader   = std::make_shared<mrs_lib::ParamLoader>(ros::NodeHandle(nh_, est_alt_agl_->getName()), "EstimationManager/" + est_alt_agl_->getName());
+     962             : 
+     963           4 :     if (_custom_config_ != "") {
+     964           4 :       ph->param_loader->addYamlFile(_custom_config_);
+     965             :     }
+     966             : 
+     967           4 :     if (_platform_config_ != "") {
+     968           4 :       ph->param_loader->addYamlFile(_platform_config_);
+     969             :     }
+     970             : 
+     971           4 :     if (_world_config_ != "") {
+     972           4 :       ph->param_loader->addYamlFile(_world_config_);
+     973             :     }
+     974             : 
+     975             :     try {
+     976           4 :       ROS_INFO("[%s]: initializing the estimator '%s'", getName().c_str(), est_alt_agl_->getName().c_str());
+     977           4 :       est_alt_agl_->initialize(nh_, ch_, ph);
+     978             :     }
+     979           0 :     catch (std::runtime_error& ex) {
+     980           0 :       ROS_ERROR("[%s]: exception caught during estimator initialization: '%s'", getName().c_str(), ex.what());
+     981           0 :       ros::shutdown();
+     982             :     }
+     983             : 
+     984           4 :     if (!est_alt_agl_->isCompatibleWithHwApi(hw_api_capabilities)) {
+     985           0 :       ROS_ERROR("[%s]: estimator %s is not compatible with the hw api. Shutting down.", getName().c_str(), est_alt_agl_->getName().c_str());
+     986           0 :       ros::shutdown();
+     987             :     }
+     988             :   }
+     989             : 
+     990           7 :   ROS_INFO("[%s]: estimators were initialized", getName().c_str());
+     991             : 
+     992             :   /*//}*/
+     993             : 
+     994             :   /*//{ initialize publishers */
+     995           7 :   ph_uav_state_    = mrs_lib::PublisherHandler<mrs_msgs::UavState>(nh_, "uav_state_out", 10);
+     996           7 :   ph_odom_main_    = mrs_lib::PublisherHandler<nav_msgs::Odometry>(nh_, "odom_main_out", 10);
+     997           7 :   ph_innovation_   = mrs_lib::PublisherHandler<nav_msgs::Odometry>(nh_, "innovation_out", 10);
+     998           7 :   ph_diagnostics_  = mrs_lib::PublisherHandler<mrs_msgs::EstimationDiagnostics>(nh_, "diagnostics_out", 10);
+     999           7 :   ph_max_flight_z_ = mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>(nh_, "max_flight_z_agl_out", 10);
+    1000           7 :   ph_altitude_agl_ = mrs_lib::PublisherHandler<mrs_msgs::Float64Stamped>(nh_, "height_agl_out", 10);
+    1001             : 
+    1002             :   /*//}*/
+    1003             : 
+    1004             :   /*//{ initialize timers */
+    1005           7 :   timer_publish_ = nh_.createTimer(ros::Rate(ch_->desired_uav_state_rate), &EstimationManager::timerPublish, this);
+    1006             : 
+    1007           7 :   timer_publish_diagnostics_ = nh_.createTimer(ros::Rate(ch_->desired_diagnostics_rate), &EstimationManager::timerPublishDiagnostics, this);
+    1008             : 
+    1009           7 :   timer_check_health_ = nh_.createTimer(ros::Rate(ch_->desired_uav_state_rate), &EstimationManager::timerCheckHealth, this);
+    1010             :   /*//}*/
+    1011             : 
+    1012             :   /*//{ initialize service clients */
+    1013             : 
+    1014           7 :   srvch_failsafe_.initialize(nh_, "failsafe_out");
+    1015             : 
+    1016             :   /*//}*/
+    1017             : 
+    1018             :   /*//{ initialize service servers */
+    1019           7 :   srvs_change_estimator_ = nh_.advertiseService("change_estimator_in", &EstimationManager::callbackChangeEstimator, this);
+    1020           7 :   srvs_toggle_callbacks_ = nh_.advertiseService("toggle_service_callbacks_in", &EstimationManager::callbackToggleServiceCallbacks, this);
+    1021             :   /*//}*/
+    1022             : 
+    1023             :   /*//{ initialize scope timer */
+    1024           7 :   param_loader.loadParam("scope_timer/enabled", ch_->scope_timer.enabled);
+    1025          14 :   std::string       filepath;
+    1026          14 :   const std::string time_logger_filepath = ros::package::getPath(package_name_) + "/scope_timer/scope_timer.txt";
+    1027           7 :   ch_->scope_timer.logger                = std::make_shared<mrs_lib::ScopeTimerLogger>(time_logger_filepath, ch_->scope_timer.enabled);
+    1028             :   /*//}*/
+    1029             : 
+    1030           7 :   if (!param_loader.loadedSuccessfully()) {
+    1031           0 :     ROS_ERROR("[%s]: Could not load all non-optional parameters. Shutting down.", getName().c_str());
+    1032           0 :     ros::shutdown();
+    1033             :   }
+    1034             : 
+    1035           7 :   sm_->changeState(StateMachine::INITIALIZED_STATE);
+    1036             : 
+    1037           7 :   ROS_INFO("[%s]: initialized", getName().c_str());
+    1038           7 : }
+    1039             : /*//}*/
+    1040             : 
+    1041             : // | -------------------- service callbacks ------------------- |
+    1042             : 
+    1043             : /*//{ callbackChangeEstimator() */
+    1044           0 : bool EstimationManager::callbackChangeEstimator(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res) {
+    1045             : 
+    1046           0 :   if (!sm_->isInitialized()) {
+    1047           0 :     return false;
+    1048             :   }
+    1049             : 
+    1050           0 :   if (!callbacks_enabled_) {
+    1051           0 :     res.success = false;
+    1052           0 :     res.message = ("Service callbacks are disabled");
+    1053           0 :     ROS_WARN("[%s]: Ignoring service call. Callbacks are disabled.", getName().c_str());
+    1054           0 :     return true;
+    1055             :   }
+    1056             : 
+    1057           0 :   if (req.value == "dummy" || req.value == "ground_truth") {
+    1058           0 :     res.success = false;
+    1059           0 :     std::stringstream ss;
+    1060           0 :     ss << "Switching to " << req.value << " estimator is not allowed.";
+    1061           0 :     res.message = ss.str();
+    1062           0 :     ROS_WARN("[%s]: Switching to %s estimator is not allowed.", getName().c_str(), req.value.c_str());
+    1063           0 :     return true;
+    1064             :   }
+    1065             : 
+    1066             :   // we do not want the switch to be disturbed by a service call
+    1067           0 :   callbacks_enabled_ = false;
+    1068             : 
+    1069           0 :   bool                                                target_estimator_found = false;
+    1070           0 :   boost::shared_ptr<mrs_uav_managers::StateEstimator> target_estimator;
+    1071           0 :   for (auto estimator : estimator_list_) {
+    1072           0 :     if (estimator->getName() == req.value) {
+    1073           0 :       target_estimator       = estimator;
+    1074           0 :       target_estimator_found = true;
+    1075           0 :       break;
+    1076             :     }
+    1077             :   }
+    1078             : 
+    1079           0 :   if (target_estimator_found) {
+    1080             : 
+    1081           0 :     if (target_estimator->isRunning()) {
+    1082           0 :       sm_->changeState(StateMachine::ESTIMATOR_SWITCHING_STATE);
+    1083           0 :       switchToEstimator(target_estimator);
+    1084           0 :       sm_->changeToPreSwitchState();
+    1085             :     } else {
+    1086           0 :       ROS_WARN("[%s]: Switch to not running estimator %s requested", getName().c_str(), req.value.c_str());
+    1087           0 :       res.success = false;
+    1088           0 :       res.message = ("Requested estimator is not running");
+    1089           0 :       return true;
+    1090             :     }
+    1091             : 
+    1092             :   } else {
+    1093           0 :     ROS_WARN("[%s]: Switch to invalid estimator %s requested", getName().c_str(), req.value.c_str());
+    1094           0 :     res.success = false;
+    1095           0 :     res.message = ("Not a valid estimator type");
+    1096           0 :     return true;
+    1097             :   }
+    1098             : 
+    1099           0 :   res.success = true;
+    1100           0 :   res.message = "Estimator switch successful";
+    1101             : 
+    1102             :   // allow service calllbacks after switch again
+    1103           0 :   callbacks_enabled_ = true;
+    1104             : 
+    1105           0 :   return true;
+    1106             : }
+    1107             : /*//}*/
+    1108             : 
+    1109             : /* //{ callbackToggleServiceCallbacks() */
+    1110          13 : bool EstimationManager::callbackToggleServiceCallbacks(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res) {
+    1111             : 
+    1112          13 :   if (!sm_->isInitialized()) {
+    1113           0 :     ROS_ERROR("[%s]: service for toggling callbacks is not available before initialization.", getName().c_str());
+    1114           0 :     return false;
+    1115             :   }
+    1116             : 
+    1117          13 :   callbacks_disabled_by_service_ = !req.data;
+    1118             : 
+    1119          13 :   res.success = true;
+    1120          13 :   res.message = (callbacks_disabled_by_service_ ? "Service callbacks disabled" : "Service callbacks enabled");
+    1121             : 
+    1122          13 :   if (callbacks_disabled_by_service_) {
+    1123             : 
+    1124           6 :     ROS_INFO("[%s]: Service callbacks disabled.", getName().c_str());
+    1125             : 
+    1126             :   } else {
+    1127             : 
+    1128           7 :     ROS_INFO("[%s]: Service callbacks enabled", getName().c_str());
+    1129             :   }
+    1130             : 
+    1131          13 :   return true;
+    1132             : }
+    1133             : 
+    1134             : //}
+    1135             : 
+    1136             : 
+    1137             : // --------------------------------------------------------------
+    1138             : // |                        other methods                       |
+    1139             : // --------------------------------------------------------------
+    1140             : //
+    1141             : /*//{ switchToHealthyEstimator() */
+    1142           0 : bool EstimationManager::switchToHealthyEstimator() {
+    1143             : 
+    1144             :   // available estimators should be specified in decreasing priority order in config file
+    1145           0 :   for (auto estimator : estimator_list_) {
+    1146           0 :     if (estimator->isRunning()) {
+    1147           0 :       switchToEstimator(estimator);
+    1148           0 :       return true;
+    1149             :     }
+    1150             :   }
+    1151           0 :   return false;  // no other estimator is running
+    1152             : }
+    1153             : /*//}*/
+    1154             : 
+    1155             : /*//{ switchToEstimator() */
+    1156           0 : void EstimationManager::switchToEstimator(const boost::shared_ptr<mrs_uav_managers::StateEstimator>& target_estimator) {
+    1157             : 
+    1158           0 :   std::scoped_lock lock(mutex_active_estimator_);
+    1159           0 :   ROS_INFO("[%s]: switching estimator from %s to %s", getName().c_str(), active_estimator_->getName().c_str(), target_estimator->getName().c_str());
+    1160           0 :   active_estimator_ = target_estimator;
+    1161           0 :   estimator_switch_count_++;
+    1162           0 : }
+    1163             : /*//}*/
+    1164             : 
+    1165             : /*//{ callFailsafeService() */
+    1166           0 : bool EstimationManager::callFailsafeService() {
+    1167           0 :   std_srvs::Trigger srv_out;
+    1168           0 :   return srvch_failsafe_.call(srv_out);
+    1169             : }
+    1170             : /*//}*/
+    1171             : 
+    1172             : /*//{ getName() */
+    1173         195 : std::string EstimationManager::getName() const {
+    1174         195 :   return nodelet_name_;
+    1175             : }
+    1176             : /*//}*/
+    1177             : 
+    1178             : /* loadConfigFile() //{ */
+    1179             : 
+    1180           0 : bool EstimationManager::loadConfigFile(const std::string& file_path) {
+    1181             : 
+    1182           0 :   const std::string name_space = nh_.getNamespace() + "/";
+    1183             : 
+    1184           0 :   ROS_INFO("[%s]: loading '%s' under the namespace '%s'", getName().c_str(), file_path.c_str(), name_space.c_str());
+    1185             : 
+    1186             :   // load the user-requested file
+    1187             :   {
+    1188           0 :     std::string command = "rosparam load " + file_path + " " + name_space;
+    1189           0 :     int         result  = std::system(command.c_str());
+    1190             : 
+    1191           0 :     if (result != 0) {
+    1192           0 :       ROS_ERROR("[%s]: failed to load '%s'", getName().c_str(), file_path.c_str());
+    1193           0 :       return false;
+    1194             :     }
+    1195             :   }
+    1196             : 
+    1197             :   // load the platform config
+    1198           0 :   if (_platform_config_ != "") {
+    1199           0 :     std::string command = "rosparam load " + _platform_config_ + " " + name_space;
+    1200           0 :     int         result  = std::system(command.c_str());
+    1201             : 
+    1202           0 :     if (result != 0) {
+    1203           0 :       ROS_ERROR("[%s]: failed to load the platform config file '%s'", getName().c_str(), _platform_config_.c_str());
+    1204           0 :       return false;
+    1205             :     }
+    1206             :   }
+    1207             : 
+    1208             :   // load the custom config
+    1209           0 :   if (_custom_config_ != "") {
+    1210           0 :     std::string command = "rosparam load " + _custom_config_ + " " + name_space;
+    1211           0 :     int         result  = std::system(command.c_str());
+    1212             : 
+    1213           0 :     if (result != 0) {
+    1214           0 :       ROS_ERROR("[%s]: failed to load the custom config file '%s'", getName().c_str(), _custom_config_.c_str());
+    1215           0 :       return false;
+    1216             :     }
+    1217             :   }
+    1218             : 
+    1219           0 :   return true;
+    1220             : }
+    1221             : 
+    1222             : //}
+    1223             : 
+    1224             : }  // namespace estimation_manager
+    1225             : 
+    1226             : }  // namespace mrs_uav_managers
+    1227             : 
+    1228             : #include <pluginlib/class_list_macros.h>
+    1229           7 : PLUGINLIB_EXPORT_CLASS(mrs_uav_managers::estimation_manager::EstimationManager, nodelet::Nodelet)
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimator.cpp.func-sort-c.html b/mrs_uav_managers/src/estimation_manager/estimator.cpp.func-sort-c.html new file mode 100644 index 0000000000..34f0df3c19 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimator.cpp.func-sort-c.html @@ -0,0 +1,164 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimator.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager - estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:618571.8 %
Date:2023-11-29 14:09:54Functions:192382.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers9Estimator12getAccGlobalERKN5boost10shared_ptrIKN11sensor_msgs4Imu_ISaIvEEEEEd0
_ZN16mrs_uav_managers9Estimator14getHeadingRateERKN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZNK16mrs_uav_managers9Estimator7getTypeB5cxx11Ev0
_ZNK16mrs_uav_managers9Estimator9isStoppedEv0
_ZN16mrs_uav_managers9Estimator11changeStateENS_18estimation_manager10SMStates_tE108
_ZN16mrs_uav_managers9Estimator17setCurrentSmStateERKNS_18estimation_manager10SMStates_tE108
_ZNK16mrs_uav_managers9Estimator23getCurrentSmStateStringB5cxx11Ev108
_ZNK16mrs_uav_managers9Estimator12getPrintNameB5cxx11Ev168
_ZNK16mrs_uav_managers9Estimator16getSmStateStringB5cxx11ERKNS_18estimation_manager10SMStates_tE216
_ZNK16mrs_uav_managers9Estimator9isStartedEv365
_ZNK16mrs_uav_managers9Estimator13getMaxFlightZEv912
_ZN16mrs_uav_managers9Estimator12getAccGlobalERKN13geometry_msgs15Vector3Stamped_ISaIvEEEd11088
_ZN16mrs_uav_managers9Estimator12getAccGlobalERKN5boost10shared_ptrIKN8mrs_msgs15EstimatorInput_ISaIvEEEEEd11104
_ZNK16mrs_uav_managers9Estimator7isReadyEv15400
_ZNK16mrs_uav_managers9Estimator10getFrameIdB5cxx11Ev23526
_ZNK16mrs_uav_managers9Estimator16isMitigatingJumpEv25491
_ZNK16mrs_uav_managers9Estimator7getNameB5cxx11Ev31092
_ZNK16mrs_uav_managers9Estimator18publishDiagnosticsEv36599
_ZNK16mrs_uav_managers9Estimator7isErrorEv44690
_ZNK16mrs_uav_managers9Estimator9isRunningEv58159
_ZNK16mrs_uav_managers9Estimator13isInitializedEv131750
_ZNK16mrs_uav_managers9Estimator9isInStateERKNS_18estimation_manager10SMStates_tE371588
_ZNK16mrs_uav_managers9Estimator17getCurrentSmStateEv393982
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimator.cpp.func.html b/mrs_uav_managers/src/estimation_manager/estimator.cpp.func.html new file mode 100644 index 0000000000..da6230fa1b --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimator.cpp.func.html @@ -0,0 +1,164 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimator.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager - estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:618571.8 %
Date:2023-11-29 14:09:54Functions:192382.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers9Estimator11changeStateENS_18estimation_manager10SMStates_tE108
_ZN16mrs_uav_managers9Estimator12getAccGlobalERKN13geometry_msgs15Vector3Stamped_ISaIvEEEd11088
_ZN16mrs_uav_managers9Estimator12getAccGlobalERKN5boost10shared_ptrIKN11sensor_msgs4Imu_ISaIvEEEEEd0
_ZN16mrs_uav_managers9Estimator12getAccGlobalERKN5boost10shared_ptrIKN8mrs_msgs15EstimatorInput_ISaIvEEEEEd11104
_ZN16mrs_uav_managers9Estimator14getHeadingRateERKN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE0
_ZN16mrs_uav_managers9Estimator17setCurrentSmStateERKNS_18estimation_manager10SMStates_tE108
_ZNK16mrs_uav_managers9Estimator10getFrameIdB5cxx11Ev23526
_ZNK16mrs_uav_managers9Estimator12getPrintNameB5cxx11Ev168
_ZNK16mrs_uav_managers9Estimator13getMaxFlightZEv912
_ZNK16mrs_uav_managers9Estimator13isInitializedEv131750
_ZNK16mrs_uav_managers9Estimator16getSmStateStringB5cxx11ERKNS_18estimation_manager10SMStates_tE216
_ZNK16mrs_uav_managers9Estimator16isMitigatingJumpEv25491
_ZNK16mrs_uav_managers9Estimator17getCurrentSmStateEv393982
_ZNK16mrs_uav_managers9Estimator18publishDiagnosticsEv36599
_ZNK16mrs_uav_managers9Estimator23getCurrentSmStateStringB5cxx11Ev108
_ZNK16mrs_uav_managers9Estimator7getNameB5cxx11Ev31092
_ZNK16mrs_uav_managers9Estimator7getTypeB5cxx11Ev0
_ZNK16mrs_uav_managers9Estimator7isErrorEv44690
_ZNK16mrs_uav_managers9Estimator7isReadyEv15400
_ZNK16mrs_uav_managers9Estimator9isInStateERKNS_18estimation_manager10SMStates_tE371588
_ZNK16mrs_uav_managers9Estimator9isRunningEv58159
_ZNK16mrs_uav_managers9Estimator9isStartedEv365
_ZNK16mrs_uav_managers9Estimator9isStoppedEv0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimator.cpp.gcov.html b/mrs_uav_managers/src/estimation_manager/estimator.cpp.gcov.html new file mode 100644 index 0000000000..cd92836ea9 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimator.cpp.gcov.html @@ -0,0 +1,282 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimator.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager - estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:618571.8 %
Date:2023-11-29 14:09:54Functions:192382.6 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_uav_managers/estimation_manager/estimator.h>
+       2             : 
+       3             : namespace mrs_uav_managers
+       4             : {
+       5             : 
+       6             : /*//{ method implementations */
+       7             : /*//{ changeState() */
+       8         108 : bool Estimator::changeState(SMStates_t new_state) {
+       9             : 
+      10         108 :   if (new_state == getCurrentSmState()) {
+      11           0 :     return true;
+      12             :   }
+      13             : 
+      14         108 :   previous_sm_state_ = getCurrentSmState();
+      15         108 :   setCurrentSmState(new_state);
+      16             : 
+      17         108 :   ROS_INFO("[%s]: Switching sm state %s -> %s", getPrintName().c_str(), getSmStateString(previous_sm_state_).c_str(), getCurrentSmStateString().c_str());
+      18         108 :   return true;
+      19             : }
+      20             : /*//}*/
+      21             : 
+      22             : /*//{ isInState() */
+      23      371588 : bool Estimator::isInState(const SMStates_t& state_in) const {
+      24      371588 :   return state_in == getCurrentSmState();
+      25             : }
+      26             : /*//}*/
+      27             : 
+      28             : /*//{ isInitialized() */
+      29      131750 : bool Estimator::isInitialized() const {
+      30      131750 :   return !isInState(UNINITIALIZED_STATE);
+      31             : }
+      32             : /*//}*/
+      33             : 
+      34             : /*//{ isReady() */
+      35       15400 : bool Estimator::isReady() const {
+      36       15400 :   return isInState(READY_STATE);
+      37             : }
+      38             : /*//}*/
+      39             : 
+      40             : /*//{ isStarted() */
+      41         365 : bool Estimator::isStarted() const {
+      42         365 :   return isInState(STARTED_STATE);
+      43             : }
+      44             : /*//}*/
+      45             : 
+      46             : /*//{ isRunning() */
+      47       58159 : bool Estimator::isRunning() const {
+      48       58159 :   return isInState(SMStates_t::RUNNING_STATE);
+      49             : }
+      50             : /*//}*/
+      51             : 
+      52             : /*//{ isStopped() */
+      53           0 : bool Estimator::isStopped() const {
+      54           0 :   return isInState(STOPPED_STATE);
+      55             : }
+      56             : /*//}*/
+      57             : 
+      58             : /*//{ isError() */
+      59       44690 : bool Estimator::isError() const {
+      60       44690 :   return isInState(ERROR_STATE);
+      61             : }
+      62             : /*//}*/
+      63             : 
+      64             : /*//{ getCurrentSmState() */
+      65      393982 : SMStates_t Estimator::getCurrentSmState() const {
+      66      393982 :   return current_sm_state_;
+      67             : }
+      68             : /*//}*/
+      69             : 
+      70             : /*//{ setCurrentSmState() */
+      71         108 : void Estimator::setCurrentSmState(const SMStates_t& new_state) {
+      72         108 :   std::scoped_lock lock(mutex_current_state_);
+      73         108 :   current_sm_state_ = new_state;
+      74         108 : }
+      75             : /*//}*/
+      76             : 
+      77             : /*//{ getSmStateString() */
+      78         216 : std::string Estimator::getSmStateString(const SMStates_t& state) const {
+      79         216 :   return sm::state_names[state];
+      80             : }
+      81             : /*//}*/
+      82             : 
+      83             : /*//{ getCurrentSmStateName() */
+      84         108 : std::string Estimator::getCurrentSmStateString(void) const {
+      85         216 :   return getSmStateString(getCurrentSmState());
+      86             : }
+      87             : /*//}*/
+      88             : 
+      89             : /*//{ isMitigatingJump() */
+      90       25491 : bool Estimator::isMitigatingJump(void) const {
+      91       25491 :   return is_mitigating_jump_;
+      92             : }
+      93             : /*//}*/
+      94             : 
+      95             : /*//{ getName() */
+      96       31092 : std::string Estimator::getName(void) const {
+      97       31092 :   return name_;
+      98             : }
+      99             : /*//}*/
+     100             : 
+     101             : /*//{ getPrintName() */
+     102         168 : std::string Estimator::getPrintName(void) const {
+     103         336 :   return ch_->nodelet_name + "/" + name_;
+     104             : }
+     105             : /*//}*/
+     106             : 
+     107             : /*//{ getType() */
+     108           0 : std::string Estimator::getType(void) const {
+     109           0 :   return type_;
+     110             : }
+     111             : /*//}*/
+     112             : 
+     113             : /*//{ getFrameId() */
+     114       23526 : std::string Estimator::getFrameId(void) const {
+     115       23526 :   return ns_frame_id_;
+     116             : }
+     117             : /*//}*/
+     118             : 
+     119             : /*//{ getMaxFlightZ() */
+     120         912 : double Estimator::getMaxFlightZ(void) const {
+     121         912 :   return max_flight_z_;
+     122             : }
+     123             : /*//}*/
+     124             : 
+     125             : /*//{ publishDiagnostics() */
+     126       36599 : void Estimator::publishDiagnostics() const {
+     127             : 
+     128       36599 :   if (!ch_->debug_topics.diag) {
+     129       36596 :     return;
+     130             :   }
+     131             : 
+     132           0 :   mrs_msgs::EstimatorDiagnostics msg;
+     133           0 :   msg.header.stamp       = ros::Time::now();
+     134           0 :   msg.header.frame_id    = getFrameId();
+     135           0 :   msg.estimator_name     = getName();
+     136           0 :   msg.estimator_type     = getType();
+     137           0 :   msg.estimator_sm_state = getCurrentSmStateString();
+     138             : 
+     139           0 :   ph_diagnostics_.publish(msg);
+     140             : }
+     141             : /*//}*/
+     142             : 
+     143             : /*//{ getAccGlobal() */
+     144           0 : tf2::Vector3 Estimator::getAccGlobal(const sensor_msgs::Imu::ConstPtr& input_msg, const double hdg) {
+     145             : 
+     146           0 :   geometry_msgs::Vector3Stamped acc_stamped;
+     147           0 :   acc_stamped.vector = input_msg->linear_acceleration;
+     148           0 :   acc_stamped.header = input_msg->header;
+     149           0 :   return getAccGlobal(acc_stamped, hdg);
+     150             : }
+     151             : 
+     152       11104 : tf2::Vector3 Estimator::getAccGlobal(const mrs_msgs::EstimatorInput::ConstPtr& input_msg, const double hdg) {
+     153             : 
+     154       22198 :   geometry_msgs::Vector3Stamped acc_stamped;
+     155       11019 :   acc_stamped.vector = input_msg->control_acceleration;
+     156       11000 :   acc_stamped.header = input_msg->header;
+     157       22148 :   return getAccGlobal(acc_stamped, hdg);
+     158             : }
+     159             : 
+     160       11088 : tf2::Vector3 Estimator::getAccGlobal(const geometry_msgs::Vector3Stamped& acc_stamped, const double hdg) {
+     161             : 
+     162             :   // untilt the desired acceleration vector
+     163       22175 :   geometry_msgs::Vector3Stamped des_acc;
+     164       11003 :   geometry_msgs::Vector3        des_acc_untilted;
+     165       11032 :   des_acc.vector.x        = acc_stamped.vector.x;
+     166       11032 :   des_acc.vector.y        = acc_stamped.vector.y;
+     167       11032 :   des_acc.vector.z        = acc_stamped.vector.z;
+     168       11032 :   des_acc.header.frame_id = ch_->frames.ns_fcu;
+     169       11042 :   des_acc.header.stamp    = acc_stamped.header.stamp;
+     170       22152 :   auto response_acc       = ch_->transformer->transformSingle(des_acc, ch_->frames.ns_fcu_untilted);
+     171       11111 :   if (response_acc) {
+     172       11111 :     des_acc_untilted.x = response_acc.value().vector.x;
+     173       11111 :     des_acc_untilted.y = response_acc.value().vector.y;
+     174       11111 :     des_acc_untilted.z = response_acc.value().vector.z;
+     175             :   } else {
+     176           0 :     ROS_WARN_THROTTLE(1.0, "[%s]: Transform from %s to %s failed", getPrintName().c_str(), des_acc.header.frame_id.c_str(),
+     177             :                       ch_->frames.ns_fcu_untilted.c_str());
+     178             :   }
+     179             : 
+     180             :   // rotate the desired acceleration vector to global frame
+     181       11111 :   const tf2::Vector3 des_acc_global = Support::rotateVecByHdg(des_acc_untilted, hdg);
+     182             : 
+     183       22181 :   return des_acc_global;
+     184             : }
+     185             : /*//}*/
+     186             : 
+     187             : /*//{ getHeadingRate() */
+     188           0 : std::optional<double> Estimator::getHeadingRate(const nav_msgs::OdometryConstPtr& odom_msg) {
+     189             : 
+     190             :   double hdg_rate;
+     191             :   try {
+     192           0 :     hdg_rate = mrs_lib::AttitudeConverter(odom_msg->pose.pose.orientation).getHeadingRate(odom_msg->twist.twist.angular);
+     193             :   }
+     194           0 :   catch (...) {
+     195           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: failed getting heading rate", getPrintName().c_str());
+     196           0 :     return {};
+     197             :   }
+     198           0 :   return hdg_rate;
+     199             : }
+     200             : /*//}*/
+     201             : 
+     202             : 
+     203             : /*//}*/
+     204             : 
+     205             : }  // namespace mrs_uav_managers
+     206             : 
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.func-sort-c.html b/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.func-sort-c.html new file mode 100644 index 0000000000..333c22f437 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimators - agl_estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:305158.8 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK16mrs_uav_managers12AglEstimator21isCompatibleWithHwApiERKN5boost10shared_ptrIKN8mrs_msgs18HwApiCapabilities_ISaIvEEEEE4
_ZNK16mrs_uav_managers12AglEstimator16publishAglHeightEv5186
_ZNK16mrs_uav_managers12AglEstimator17publishCovarianceEv5186
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.func.html b/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.func.html new file mode 100644 index 0000000000..bb4294c7a9 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimators - agl_estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:305158.8 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK16mrs_uav_managers12AglEstimator16publishAglHeightEv5186
_ZNK16mrs_uav_managers12AglEstimator17publishCovarianceEv5186
_ZNK16mrs_uav_managers12AglEstimator21isCompatibleWithHwApiERKN5boost10shared_ptrIKN8mrs_msgs18HwApiCapabilities_ISaIvEEEEE4
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.gcov.html b/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.gcov.html new file mode 100644 index 0000000000..08ebda3ad0 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp.gcov.html @@ -0,0 +1,174 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators/agl_estimator.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimators - agl_estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:305158.8 %
Date:2023-11-29 14:09:54Functions:33100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_uav_managers/agl_estimator.h>
+       2             : 
+       3             : namespace mrs_uav_managers
+       4             : {
+       5             : 
+       6             : /*//{ publishAglHeight() */
+       7        5186 : void AglEstimator::publishAglHeight() const {
+       8        5186 :   ph_agl_height_.publish(mrs_lib::get_mutexed(mtx_agl_height_, agl_height_));
+       9        5186 : }
+      10             : /*//}*/
+      11             : 
+      12             : /*//{ publishCovariance() */
+      13        5186 : void AglEstimator::publishCovariance() const {
+      14             : 
+      15        5186 :   if (!ch_->debug_topics.covariance) {
+      16        5186 :     return;
+      17             :   }
+      18             : 
+      19           0 :   ph_agl_height_cov_.publish(mrs_lib::get_mutexed(mtx_agl_height_, agl_height_cov_));
+      20             : }
+      21             : /*//}*/
+      22             : 
+      23             : /*//{ isCompatibleWithHwApi() */
+      24           4 : bool AglEstimator::isCompatibleWithHwApi(const mrs_msgs::HwApiCapabilitiesConstPtr& hw_api_capabilities) const {
+      25             : 
+      26           4 :   ph_->param_loader->addYamlFile(ros::package::getPath(package_name_) + "/config/private/" + getName() + "/" + getName() + ".yaml");
+      27           4 :   ph_->param_loader->addYamlFile(ros::package::getPath(package_name_) + "/config/public/" + getName() + "/" + getName() + ".yaml");
+      28             : 
+      29           4 :   ph_->param_loader->setPrefix(ch_->package_name + "/" + Support::toSnakeCase(ch_->nodelet_name) + "/" + getName() + "/");
+      30             : 
+      31             :   bool requires_gnss, requires_imu, requires_distance_sensor, requires_altitude, requires_magnetometer_heading, requires_position, requires_orientation,
+      32             :       requires_velocity, requires_angular_velocity;
+      33             : 
+      34           4 :   ph_->param_loader->loadParam("requires/gnss", requires_gnss);
+      35           4 :   ph_->param_loader->loadParam("requires/imu", requires_imu);
+      36           4 :   ph_->param_loader->loadParam("requires/distance_sensor", requires_distance_sensor);
+      37           4 :   ph_->param_loader->loadParam("requires/altitude", requires_altitude);
+      38           4 :   ph_->param_loader->loadParam("requires/magnetometer_heading", requires_magnetometer_heading);
+      39           4 :   ph_->param_loader->loadParam("requires/position", requires_position);
+      40           4 :   ph_->param_loader->loadParam("requires/orientation", requires_orientation);
+      41           4 :   ph_->param_loader->loadParam("requires/velocity", requires_velocity);
+      42           4 :   ph_->param_loader->loadParam("requires/angular_velocity", requires_angular_velocity);
+      43             : 
+      44           4 :   if (!ph_->param_loader->loadedSuccessfully()) {
+      45           0 :     ROS_ERROR("[%s]: Could not load all non-optional parameters. Shutting down.", getPrintName().c_str());
+      46           0 :     ros::shutdown();
+      47             :   }
+      48             : 
+      49           4 :   if (requires_gnss && !hw_api_capabilities->produces_gnss) {
+      50           0 :     ROS_ERROR("[%s]: requires gnss but hw api does not provide it.", getPrintName().c_str());
+      51           0 :     return false;
+      52             :   }
+      53             : 
+      54           4 :   if (requires_imu && !hw_api_capabilities->produces_imu) {
+      55           0 :     ROS_ERROR("[%s]: requires imu but hw api does not provide it.", getPrintName().c_str());
+      56           0 :     return false;
+      57             :   }
+      58             : 
+      59           4 :   if (requires_distance_sensor && !hw_api_capabilities->produces_distance_sensor) {
+      60           0 :     ROS_ERROR("[%s]: requires distance_sensor but hw api does not provide it.", getPrintName().c_str());
+      61           0 :     return false;
+      62             :   }
+      63             : 
+      64           4 :   if (requires_altitude && !hw_api_capabilities->produces_altitude) {
+      65           0 :     ROS_ERROR("[%s]: requires altitude but hw api does not provide it.", getPrintName().c_str());
+      66           0 :     return false;
+      67             :   }
+      68             : 
+      69           4 :   if (requires_magnetometer_heading && !hw_api_capabilities->produces_magnetometer_heading) {
+      70           0 :     ROS_ERROR("[%s]: requires magnetometer_heading but hw api does not provide it.", getPrintName().c_str());
+      71           0 :     return false;
+      72             :   }
+      73             : 
+      74           4 :   if (requires_position && !hw_api_capabilities->produces_position) {
+      75           0 :     ROS_ERROR("[%s]: requires position but hw api does not provide it.", getPrintName().c_str());
+      76           0 :     return false;
+      77             :   }
+      78             : 
+      79           4 :   if (requires_orientation && !hw_api_capabilities->produces_orientation) {
+      80           0 :     ROS_ERROR("[%s]: requires orientation but hw api does not provide it.", getPrintName().c_str());
+      81           0 :     return false;
+      82             :   }
+      83             : 
+      84           4 :   if (requires_velocity && !hw_api_capabilities->produces_velocity) {
+      85           0 :     ROS_ERROR("[%s]: requires velocity but hw api does not provide it.", getPrintName().c_str());
+      86           0 :     return false;
+      87             :   }
+      88             : 
+      89           4 :   if (requires_angular_velocity && !hw_api_capabilities->produces_angular_velocity) {
+      90           0 :     ROS_ERROR("[%s]: requires angular_velocity but hw api does not provide it.", getPrintName().c_str());
+      91           0 :     return false;
+      92             :   }
+      93             : 
+      94           4 :   return true;
+      95             : }
+      96             : /*//}*/
+      97             : 
+      98             : }  // namespace mrs_uav_managers
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/index-sort-f.html b/mrs_uav_managers/src/estimation_manager/estimators/index-sort-f.html new file mode 100644 index 0000000000..1514f1d2be --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimatorsHitTotalCoverage
Test:coverage.infoLines:8213560.7 %
Date:2023-11-29 14:09:54Functions:1313100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
agl_estimator.cpp +
58.8%58.8%
+
58.8 %30 / 51100.0 %3 / 3
state_estimator.cpp +
61.9%61.9%
+
61.9 %52 / 84100.0 %10 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/index-sort-l.html b/mrs_uav_managers/src/estimation_manager/estimators/index-sort-l.html new file mode 100644 index 0000000000..c7da9af85b --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimatorsHitTotalCoverage
Test:coverage.infoLines:8213560.7 %
Date:2023-11-29 14:09:54Functions:1313100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
agl_estimator.cpp +
58.8%58.8%
+
58.8 %30 / 51100.0 %3 / 3
state_estimator.cpp +
61.9%61.9%
+
61.9 %52 / 84100.0 %10 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/index.html b/mrs_uav_managers/src/estimation_manager/estimators/index.html new file mode 100644 index 0000000000..c9cc5e6551 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimatorsHitTotalCoverage
Test:coverage.infoLines:8213560.7 %
Date:2023-11-29 14:09:54Functions:1313100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
agl_estimator.cpp +
58.8%58.8%
+
58.8 %30 / 51100.0 %3 / 3
state_estimator.cpp +
61.9%61.9%
+
61.9 %52 / 84100.0 %10 / 10
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.func-sort-c.html b/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.func-sort-c.html new file mode 100644 index 0000000000..00e0404ffe --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.func-sort-c.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimators - state_estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:528461.9 %
Date:2023-11-29 14:09:54Functions:1010100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZNK16mrs_uav_managers14StateEstimator21isCompatibleWithHwApiERKN5boost10shared_ptrIKN8mrs_msgs18HwApiCapabilities_ISaIvEEEEE7
_ZNK16mrs_uav_managers14StateEstimator13getInnovationEv8946
_ZNK16mrs_uav_managers14StateEstimator17getPoseCovarianceEv8946
_ZNK16mrs_uav_managers14StateEstimator18getTwistCovarianceEv8946
_ZNK16mrs_uav_managers14StateEstimator11publishOdomEv9679
_ZNK16mrs_uav_managers14StateEstimator15publishUavStateEv9679
_ZNK16mrs_uav_managers14StateEstimator17publishCovarianceEv9679
_ZNK16mrs_uav_managers14StateEstimator17publishInnovationEv9679
_ZN16mrs_uav_managers14StateEstimator11getUavStateEv9842
_ZNK16mrs_uav_managers14StateEstimator25rotateQuaternionByHeadingERKN13geometry_msgs11Quaternion_ISaIvEEEd11030
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.func.html b/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.func.html new file mode 100644 index 0000000000..b3c46a1975 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.func.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimators - state_estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:528461.9 %
Date:2023-11-29 14:09:54Functions:1010100.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers14StateEstimator11getUavStateEv9842
_ZNK16mrs_uav_managers14StateEstimator11publishOdomEv9679
_ZNK16mrs_uav_managers14StateEstimator13getInnovationEv8946
_ZNK16mrs_uav_managers14StateEstimator15publishUavStateEv9679
_ZNK16mrs_uav_managers14StateEstimator17getPoseCovarianceEv8946
_ZNK16mrs_uav_managers14StateEstimator17publishCovarianceEv9679
_ZNK16mrs_uav_managers14StateEstimator17publishInnovationEv9679
_ZNK16mrs_uav_managers14StateEstimator18getTwistCovarianceEv8946
_ZNK16mrs_uav_managers14StateEstimator21isCompatibleWithHwApiERKN5boost10shared_ptrIKN8mrs_msgs18HwApiCapabilities_ISaIvEEEEE7
_ZNK16mrs_uav_managers14StateEstimator25rotateQuaternionByHeadingERKN13geometry_msgs11Quaternion_ISaIvEEEd11030
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.gcov.html b/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.gcov.html new file mode 100644 index 0000000000..75cf0b460f --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp.gcov.html @@ -0,0 +1,255 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager/estimators/state_estimator.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_manager/estimators - state_estimator.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:528461.9 %
Date:2023-11-29 14:09:54Functions:1010100.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <mrs_uav_managers/state_estimator.h>
+       2             : 
+       3             : namespace mrs_uav_managers
+       4             : {
+       5             : 
+       6             : 
+       7             : /*//{ getUavState() */
+       8        9842 : std::optional<mrs_msgs::UavState> StateEstimator::getUavState() {
+       9             : 
+      10        9842 :   if (!isRunning()) {
+      11           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: getUavState() was called while estimator is not running", getPrintName().c_str());
+      12           0 :     return {};
+      13             :   }
+      14             : 
+      15       19671 :   return mrs_lib::get_mutexed(mtx_uav_state_, uav_state_);
+      16             : }
+      17             : /*//}*/
+      18             : 
+      19             : /*//{ getInnovation() */
+      20        8946 : nav_msgs::Odometry StateEstimator::getInnovation() const {
+      21        8946 :   return mrs_lib::get_mutexed(mtx_innovation_, innovation_);
+      22             : }
+      23             : /*//}*/
+      24             : 
+      25             : /*//{ getPoseCovariance() */
+      26        8946 : std::vector<double> StateEstimator::getPoseCovariance() const {
+      27        8946 :   return mrs_lib::get_mutexed(mtx_covariance_, pose_covariance_.values);
+      28             : }
+      29             : /*//}*/
+      30             : 
+      31             : /*//{ getTwistCovariance() */
+      32        8946 : std::vector<double> StateEstimator::getTwistCovariance() const {
+      33        8946 :   return mrs_lib::get_mutexed(mtx_covariance_, twist_covariance_.values);
+      34             : }
+      35             : /*//}*/
+      36             : 
+      37             : /*//{ publishUavState() */
+      38        9679 : void StateEstimator::publishUavState() const {
+      39             : 
+      40        9679 :   if (!ch_->debug_topics.state) {
+      41           0 :     return;
+      42             :   }
+      43             : 
+      44       19358 :   auto uav_state = mrs_lib::get_mutexed(mtx_uav_state_, uav_state_);
+      45        9679 :   ph_uav_state_.publish(uav_state);
+      46             : }
+      47             : /*//}*/
+      48             : 
+      49             : /*//{ publishOdom() */
+      50        9679 : void StateEstimator::publishOdom() const {
+      51             : 
+      52       19358 :   auto odom = mrs_lib::get_mutexed(mtx_odom_, odom_);
+      53        9679 :   ph_odom_.publish(odom);
+      54        9679 : }
+      55             : /*//}*/
+      56             : 
+      57             : /*//{ publishCovariance() */
+      58        9679 : void StateEstimator::publishCovariance() const {
+      59             : 
+      60        9679 :   if (!ch_->debug_topics.covariance) {
+      61        9679 :     return;
+      62             :   }
+      63             : 
+      64           0 :   auto pose_cov  = mrs_lib::get_mutexed(mtx_covariance_, pose_covariance_);
+      65           0 :   auto twist_cov = mrs_lib::get_mutexed(mtx_covariance_, twist_covariance_);
+      66           0 :   ph_pose_covariance_.publish(pose_cov);
+      67           0 :   ph_twist_covariance_.publish(twist_cov);
+      68             : }
+      69             : /*//}*/
+      70             : 
+      71             : /*//{ publishInnovation() */
+      72        9679 : void StateEstimator::publishInnovation() const {
+      73             : 
+      74        9679 :   if (!ch_->debug_topics.innovation) {
+      75        9679 :     return;
+      76             :   }
+      77             : 
+      78           0 :   auto innovation = mrs_lib::get_mutexed(mtx_innovation_, innovation_);
+      79           0 :   ph_innovation_.publish(innovation);
+      80             : }
+      81             : /*//}*/
+      82             : 
+      83             : /*//{ rotateQuaternionByHeading() */
+      84       11030 : std::optional<geometry_msgs::Quaternion> StateEstimator::rotateQuaternionByHeading(const geometry_msgs::Quaternion& q, const double hdg) const {
+      85             : 
+      86             :   try {
+      87       11030 :     tf2::Quaternion tf2_q = mrs_lib::AttitudeConverter(q);
+      88             : 
+      89             :     // Obtain heading from quaternion
+      90       11030 :     double q_hdg = 0;
+      91       11030 :     q_hdg        = mrs_lib::AttitudeConverter(q).getHeading();
+      92             : 
+      93             :     // Build rotation matrix from difference between new heading and quaternion heading
+      94       11012 :     tf2::Matrix3x3 rot_mat = mrs_lib::AttitudeConverter(Eigen::AngleAxisd(hdg - q_hdg, Eigen::Vector3d::UnitZ()));
+      95             : 
+      96             :     // Transform the quaternion orientation by the rotation matrix
+      97       10958 :     geometry_msgs::Quaternion q_new = mrs_lib::AttitudeConverter(tf2::Transform(rot_mat) * tf2_q);
+      98       11002 :     return q_new;
+      99             :   }
+     100           0 :   catch (...) {
+     101           0 :     ROS_WARN("[rotateQuaternionByHeading()]: failed to rotate quaternion by heading");
+     102           0 :     return {};
+     103             :   }
+     104             : }
+     105             : /*//}*/
+     106             : 
+     107             : /*//{ isCompatibleWithHwApi() */
+     108           7 : bool StateEstimator::isCompatibleWithHwApi(const mrs_msgs::HwApiCapabilitiesConstPtr& hw_api_capabilities) const {
+     109             : 
+     110           7 :   ph_->param_loader->setPrefix(ch_->package_name + "/" + Support::toSnakeCase(ch_->nodelet_name) + "/" + getName() + "/");
+     111             : 
+     112             :   bool requires_gnss, requires_imu, requires_distance_sensor, requires_altitude, requires_magnetometer_heading, requires_position, requires_orientation,
+     113             :       requires_velocity, requires_angular_velocity;
+     114             : 
+     115           7 :   ph_->param_loader->loadParam("requires/gnss", requires_gnss);
+     116           7 :   ph_->param_loader->loadParam("requires/imu", requires_imu);
+     117           7 :   ph_->param_loader->loadParam("requires/distance_sensor", requires_distance_sensor);
+     118           7 :   ph_->param_loader->loadParam("requires/altitude", requires_altitude);
+     119           7 :   ph_->param_loader->loadParam("requires/magnetometer_heading", requires_magnetometer_heading);
+     120           7 :   ph_->param_loader->loadParam("requires/position", requires_position);
+     121           7 :   ph_->param_loader->loadParam("requires/orientation", requires_orientation);
+     122           7 :   ph_->param_loader->loadParam("requires/velocity", requires_velocity);
+     123           7 :   ph_->param_loader->loadParam("requires/angular_velocity", requires_angular_velocity);
+     124             : 
+     125           7 :   if (!ph_->param_loader->loadedSuccessfully()) {
+     126           0 :     ROS_ERROR("[%s]: Could not load all non-optional hw_api compatibility parameters. Shutting down.", getPrintName().c_str());
+     127           0 :     ros::shutdown();
+     128             :   }
+     129             : 
+     130           7 :   if (requires_gnss && !hw_api_capabilities->produces_gnss) {
+     131           0 :     ROS_ERROR("[%s]: requires gnss but hw api does not provide it.", getPrintName().c_str());
+     132           0 :     return false;
+     133             :   }
+     134             : 
+     135           7 :   if (requires_imu && !hw_api_capabilities->produces_imu) {
+     136           0 :     ROS_ERROR("[%s]: requires imu but hw api does not provide it.", getPrintName().c_str());
+     137           0 :     return false;
+     138             :   }
+     139             : 
+     140           7 :   if (requires_distance_sensor && !hw_api_capabilities->produces_distance_sensor) {
+     141           0 :     ROS_ERROR("[%s]: requires distance_sensor but hw api does not provide it.", getPrintName().c_str());
+     142           0 :     return false;
+     143             :   }
+     144             : 
+     145           7 :   if (requires_altitude && !hw_api_capabilities->produces_altitude) {
+     146           0 :     ROS_ERROR("[%s]: requires altitude but hw api does not provide it.", getPrintName().c_str());
+     147           0 :     return false;
+     148             :   }
+     149             : 
+     150           7 :   if (requires_magnetometer_heading && !hw_api_capabilities->produces_magnetometer_heading) {
+     151           0 :     ROS_ERROR("[%s]: requires magnetometer_heading but hw api does not provide it.", getPrintName().c_str());
+     152           0 :     return false;
+     153             :   }
+     154             : 
+     155           7 :   if (requires_position && !hw_api_capabilities->produces_position) {
+     156           0 :     ROS_ERROR("[%s]: requires position but hw api does not provide it.", getPrintName().c_str());
+     157           0 :     return false;
+     158             :   }
+     159             : 
+     160           7 :   if (requires_orientation && !hw_api_capabilities->produces_orientation) {
+     161           0 :     ROS_ERROR("[%s]: requires orientation but hw api does not provide it.", getPrintName().c_str());
+     162           0 :     return false;
+     163             :   }
+     164             : 
+     165           7 :   if (requires_velocity && !hw_api_capabilities->produces_velocity) {
+     166           0 :     ROS_ERROR("[%s]: requires velocity but hw api does not provide it.", getPrintName().c_str());
+     167           0 :     return false;
+     168             :   }
+     169             : 
+     170           7 :   if (requires_angular_velocity && !hw_api_capabilities->produces_angular_velocity) {
+     171           0 :     ROS_ERROR("[%s]: requires angular_velocity but hw api does not provide it.", getPrintName().c_str());
+     172           0 :     return false;
+     173             :   }
+     174             : 
+     175           7 :   return true;
+     176             : }
+     177             : /*//}*/
+     178             : 
+     179             : }  // namespace mrs_uav_managers
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/index-sort-f.html b/mrs_uav_managers/src/estimation_manager/index-sort-f.html new file mode 100644 index 0000000000..540e1d61ce --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/index-sort-f.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_managerHitTotalCoverage
Test:coverage.infoLines:39161363.8 %
Date:2023-11-29 14:09:54Functions:374778.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
estimation_manager.cpp +
62.5%62.5%
+
62.5 %330 / 52875.0 %18 / 24
estimator.cpp +
71.8%71.8%
+
71.8 %61 / 8582.6 %19 / 23
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/index-sort-l.html b/mrs_uav_managers/src/estimation_manager/index-sort-l.html new file mode 100644 index 0000000000..2b4d02c85f --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/index-sort-l.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_managerHitTotalCoverage
Test:coverage.infoLines:39161363.8 %
Date:2023-11-29 14:09:54Functions:374778.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
estimation_manager.cpp +
62.5%62.5%
+
62.5 %330 / 52875.0 %18 / 24
estimator.cpp +
71.8%71.8%
+
71.8 %61 / 8582.6 %19 / 23
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/estimation_manager/index.html b/mrs_uav_managers/src/estimation_manager/index.html new file mode 100644 index 0000000000..663f1b3303 --- /dev/null +++ b/mrs_uav_managers/src/estimation_manager/index.html @@ -0,0 +1,103 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/estimation_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/estimation_managerHitTotalCoverage
Test:coverage.infoLines:39161363.8 %
Date:2023-11-29 14:09:54Functions:374778.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
estimation_manager.cpp +
62.5%62.5%
+
62.5 %330 / 52875.0 %18 / 24
estimator.cpp +
71.8%71.8%
+
71.8 %61 / 8582.6 %19 / 23
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/gain_manager.cpp.func-sort-c.html b/mrs_uav_managers/src/gain_manager.cpp.func-sort-c.html new file mode 100644 index 0000000000..0d30256b56 --- /dev/null +++ b/mrs_uav_managers/src/gain_manager.cpp.func-sort-c.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/gain_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - gain_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:20225379.8 %
Date:2023-11-29 14:09:54Functions:6785.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers12gain_manager11GainManager16callbackSetGainsERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE0
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers12gain_manager11GainManager6onInitEv7
_ZN16mrs_uav_managers12gain_manager11GainManager8setGainsENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
_ZN16mrs_uav_managers12gain_manager11GainManager16timerDiagnosticsERKN3ros10TimerEventE116
_ZN16mrs_uav_managers12gain_manager11GainManager14stringInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS7_SaIS7_EE154
_ZN16mrs_uav_managers12gain_manager11GainManager19timerGainManagementERKN3ros10TimerEventE1190
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/gain_manager.cpp.func.html b/mrs_uav_managers/src/gain_manager.cpp.func.html new file mode 100644 index 0000000000..58c4201964 --- /dev/null +++ b/mrs_uav_managers/src/gain_manager.cpp.func.html @@ -0,0 +1,100 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/gain_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - gain_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:20225379.8 %
Date:2023-11-29 14:09:54Functions:6785.7 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers12gain_manager11GainManager14stringInVectorERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS7_SaIS7_EE154
_ZN16mrs_uav_managers12gain_manager11GainManager16callbackSetGainsERN8mrs_msgs14StringRequest_ISaIvEEERNS2_15StringResponse_IS4_EE0
_ZN16mrs_uav_managers12gain_manager11GainManager16timerDiagnosticsERKN3ros10TimerEventE116
_ZN16mrs_uav_managers12gain_manager11GainManager19timerGainManagementERKN3ros10TimerEventE1190
_ZN16mrs_uav_managers12gain_manager11GainManager6onInitEv7
_ZN16mrs_uav_managers12gain_manager11GainManager8setGainsENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE7
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/gain_manager.cpp.gcov.html b/mrs_uav_managers/src/gain_manager.cpp.gcov.html new file mode 100644 index 0000000000..86f63c9af5 --- /dev/null +++ b/mrs_uav_managers/src/gain_manager.cpp.gcov.html @@ -0,0 +1,712 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/gain_manager.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - gain_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:20225379.8 %
Date:2023-11-29 14:09:54Functions:6785.7 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /* includes //{ */
+       2             : 
+       3             : #include <ros/ros.h>
+       4             : #include <nodelet/nodelet.h>
+       5             : 
+       6             : #include <std_msgs/String.h>
+       7             : 
+       8             : #include <mrs_msgs/String.h>
+       9             : #include <mrs_msgs/EstimationDiagnostics.h>
+      10             : #include <mrs_msgs/ControlManagerDiagnostics.h>
+      11             : #include <mrs_msgs/GainManagerDiagnostics.h>
+      12             : 
+      13             : #include <mrs_lib/profiler.h>
+      14             : #include <mrs_lib/scope_timer.h>
+      15             : #include <mrs_lib/param_loader.h>
+      16             : #include <mrs_lib/mutex.h>
+      17             : #include <mrs_lib/publisher_handler.h>
+      18             : #include <mrs_lib/service_client_handler.h>
+      19             : #include <mrs_lib/subscribe_handler.h>
+      20             : 
+      21             : #include <dynamic_reconfigure/ReconfigureRequest.h>
+      22             : #include <dynamic_reconfigure/Reconfigure.h>
+      23             : #include <dynamic_reconfigure/Config.h>
+      24             : 
+      25             : //}
+      26             : 
+      27             : namespace mrs_uav_managers
+      28             : {
+      29             : 
+      30             : namespace gain_manager
+      31             : {
+      32             : 
+      33             : /* //{ class GainManager */
+      34             : 
+      35             : typedef struct
+      36             : {
+      37             : 
+      38             :   double kpxy, kiwxy, kibxy, kvxy, kaxy;
+      39             :   double kpz, kvz, kaz;
+      40             :   double kiwxy_lim, kibxy_lim;
+      41             :   double km, km_lim;
+      42             :   double kqrp, kqy;
+      43             : 
+      44             :   std::string name;
+      45             : 
+      46             : } Gains_t;
+      47             : 
+      48             : class GainManager : public nodelet::Nodelet {
+      49             : 
+      50             : public:
+      51             :   virtual void onInit();
+      52             : 
+      53             : private:
+      54             :   ros::NodeHandle nh_;
+      55             :   bool            is_initialized_ = false;
+      56             : 
+      57             :   // | ----------------------- parameters ----------------------- |
+      58             : 
+      59             :   std::vector<std::string> _current_state_estimators_;
+      60             : 
+      61             :   std::vector<std::string>       _gain_names_;
+      62             :   std::map<std::string, Gains_t> _gains_;
+      63             : 
+      64             :   std::map<std::string, std::vector<std::string>> _map_type_allowed_gains_;
+      65             :   std::map<std::string, std::string>              _map_type_default_gains_;
+      66             :   ;
+      67             : 
+      68             :   // | --------------------- service clients -------------------- |
+      69             : 
+      70             :   ros::ServiceClient service_client_set_gains_;
+      71             : 
+      72             :   // | ----------------------- subscribers ---------------------- |
+      73             : 
+      74             :   mrs_lib::SubscribeHandler<mrs_msgs::EstimationDiagnostics>     sh_estimation_diag_;
+      75             :   mrs_lib::SubscribeHandler<mrs_msgs::ControlManagerDiagnostics> sh_control_manager_diag_;
+      76             : 
+      77             :   // | --------------------- gain management -------------------- |
+      78             : 
+      79             :   bool setGains(std::string gains_name);
+      80             : 
+      81             :   ros::ServiceServer service_server_set_gains_;
+      82             :   bool               callbackSetGains(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res);
+      83             : 
+      84             :   std::string last_estimator_name_;
+      85             :   std::mutex  mutex_last_estimator_name_;
+      86             : 
+      87             :   void       timerGainManagement(const ros::TimerEvent& event);
+      88             :   ros::Timer timer_gain_management_;
+      89             :   double     _gain_management_rate_;
+      90             : 
+      91             :   std::string current_gains_;
+      92             :   std::mutex  mutex_current_gains_;
+      93             : 
+      94             :   // | ------------------ diagnostics publisher ----------------- |
+      95             : 
+      96             :   mrs_lib::PublisherHandler<mrs_msgs::GainManagerDiagnostics> ph_diagnostics_;
+      97             : 
+      98             :   void       timerDiagnostics(const ros::TimerEvent& event);
+      99             :   ros::Timer timer_diagnostics_;
+     100             :   double     _diagnostics_rate_;
+     101             : 
+     102             :   // | ------------------------ profiler ------------------------ |
+     103             : 
+     104             :   mrs_lib::Profiler profiler_;
+     105             :   bool              _profiler_enabled_ = false;
+     106             : 
+     107             :   // | ------------------- scope timer logger ------------------- |
+     108             : 
+     109             :   bool                                       scope_timer_enabled_ = false;
+     110             :   std::shared_ptr<mrs_lib::ScopeTimerLogger> scope_timer_logger_;
+     111             : 
+     112             :   // | ------------------------- helpers ------------------------ |
+     113             : 
+     114             :   bool stringInVector(const std::string& value, const std::vector<std::string>& vector);
+     115             : };
+     116             : 
+     117             : //}
+     118             : 
+     119             : /* //{ onInit() */
+     120             : 
+     121           7 : void GainManager::onInit() {
+     122             : 
+     123          14 :   ros::NodeHandle nh_ = nodelet::Nodelet::getMTPrivateNodeHandle();
+     124             : 
+     125           7 :   ros::Time::waitForValid();
+     126             : 
+     127           7 :   ROS_INFO("[GainManager]: initializing");
+     128             : 
+     129             :   // | ------------------------- params ------------------------- |
+     130             : 
+     131          14 :   mrs_lib::ParamLoader param_loader(nh_, "GainManager");
+     132             : 
+     133          14 :   std::string custom_config_path;
+     134          14 :   std::string platform_config_path;
+     135             : 
+     136           7 :   param_loader.loadParam("custom_config", custom_config_path);
+     137           7 :   param_loader.loadParam("platform_config", platform_config_path);
+     138             : 
+     139           7 :   if (custom_config_path != "") {
+     140           7 :     param_loader.addYamlFile(custom_config_path);
+     141             :   }
+     142             : 
+     143           7 :   if (platform_config_path != "") {
+     144           7 :     param_loader.addYamlFile(platform_config_path);
+     145             :   }
+     146             : 
+     147           7 :   param_loader.addYamlFileFromParam("private_config");
+     148           7 :   param_loader.addYamlFileFromParam("public_config");
+     149           7 :   param_loader.addYamlFileFromParam("public_gains");
+     150             : 
+     151          14 :   const std::string yaml_prefix = "mrs_uav_managers/gain_manager/";
+     152             : 
+     153             :   // params passed from the launch file are not prefixed
+     154           7 :   param_loader.loadParam("enable_profiler", _profiler_enabled_);
+     155             : 
+     156           7 :   param_loader.loadParam(yaml_prefix + "gains", _gain_names_);
+     157             : 
+     158           7 :   param_loader.loadParam(yaml_prefix + "estimator_types", _current_state_estimators_);
+     159             : 
+     160           7 :   param_loader.loadParam(yaml_prefix + "rate", _gain_management_rate_);
+     161           7 :   param_loader.loadParam(yaml_prefix + "diagnostics_rate", _diagnostics_rate_);
+     162             : 
+     163             :   // | ------------------- scope timer logger ------------------- |
+     164             : 
+     165           7 :   param_loader.loadParam(yaml_prefix + "scope_timer/enabled", scope_timer_enabled_);
+     166          21 :   const std::string scope_timer_log_filename = param_loader.loadParam2("scope_timer/log_filename", std::string(""));
+     167           7 :   scope_timer_logger_                        = std::make_shared<mrs_lib::ScopeTimerLogger>(scope_timer_log_filename, scope_timer_enabled_);
+     168             : 
+     169           7 :   std::vector<std::string>::iterator it;
+     170             : 
+     171             :   // loading gain_names
+     172          21 :   for (it = _gain_names_.begin(); it != _gain_names_.end(); ++it) {
+     173             : 
+     174          14 :     ROS_INFO_STREAM("[GainManager]: loading gains '" << *it << "'");
+     175             : 
+     176          14 :     Gains_t new_gains;
+     177             : 
+     178          14 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/kp", new_gains.kpxy);
+     179          14 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/kv", new_gains.kvxy);
+     180          14 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/ka", new_gains.kaxy);
+     181          14 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/kib", new_gains.kibxy);
+     182          14 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/kiw", new_gains.kiwxy);
+     183          14 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/kib_lim", new_gains.kibxy_lim);
+     184          14 :     param_loader.loadParam(yaml_prefix + *it + "/horizontal/kiw_lim", new_gains.kiwxy_lim);
+     185             : 
+     186          14 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/kp", new_gains.kpz);
+     187          14 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/kv", new_gains.kvz);
+     188          14 :     param_loader.loadParam(yaml_prefix + *it + "/vertical/ka", new_gains.kaz);
+     189             : 
+     190          14 :     param_loader.loadParam(yaml_prefix + *it + "/attitude/kq_roll_pitch", new_gains.kqrp);
+     191          14 :     param_loader.loadParam(yaml_prefix + *it + "/attitude/kq_yaw", new_gains.kqy);
+     192             : 
+     193          14 :     param_loader.loadParam(yaml_prefix + *it + "/mass_estimator/km", new_gains.km);
+     194          14 :     param_loader.loadParam(yaml_prefix + *it + "/mass_estimator/km_lim", new_gains.km_lim);
+     195             : 
+     196          14 :     _gains_.insert(std::pair<std::string, Gains_t>(*it, new_gains));
+     197             :   }
+     198             : 
+     199             :   // loading the allowed gains lists
+     200          56 :   for (it = _current_state_estimators_.begin(); it != _current_state_estimators_.end(); ++it) {
+     201             : 
+     202          49 :     std::vector<std::string> temp_vector;
+     203          49 :     param_loader.loadParam(yaml_prefix + "allowed_gains/" + *it, temp_vector);
+     204             : 
+     205          49 :     std::vector<std::string>::iterator it2;
+     206         147 :     for (it2 = temp_vector.begin(); it2 != temp_vector.end(); ++it2) {
+     207          98 :       if (!stringInVector(*it2, _gain_names_)) {
+     208           0 :         ROS_ERROR("[GainManager]: the element '%s' of %s/allowed_gains is not a valid gain!", it2->c_str(), it->c_str());
+     209           0 :         ros::shutdown();
+     210             :       }
+     211             :     }
+     212             : 
+     213          49 :     _map_type_allowed_gains_.insert(std::pair<std::string, std::vector<std::string>>(*it, temp_vector));
+     214             :   }
+     215             : 
+     216             :   // loading the default gains
+     217          56 :   for (it = _current_state_estimators_.begin(); it != _current_state_estimators_.end(); ++it) {
+     218             : 
+     219          49 :     std::string temp_str;
+     220          49 :     param_loader.loadParam(yaml_prefix + "default_gains/" + *it, temp_str);
+     221             : 
+     222          49 :     if (!stringInVector(temp_str, _map_type_allowed_gains_.at(*it))) {
+     223           0 :       ROS_ERROR("[GainManager]: the element '%s' of %s/allowed_gains is not a valid gain!", temp_str.c_str(), it->c_str());
+     224           0 :       ros::shutdown();
+     225             :     }
+     226             : 
+     227          49 :     _map_type_default_gains_.insert(std::pair<std::string, std::string>(*it, temp_str));
+     228             :   }
+     229             : 
+     230           7 :   ROS_INFO("[GainManager]: done loading dynamical params");
+     231             : 
+     232           7 :   current_gains_       = "";
+     233           7 :   last_estimator_name_ = "";
+     234             : 
+     235             :   // | ------------------------ services ------------------------ |
+     236             : 
+     237           7 :   service_server_set_gains_ = nh_.advertiseService("set_gains_in", &GainManager::callbackSetGains, this);
+     238             : 
+     239           7 :   service_client_set_gains_ = nh_.serviceClient<dynamic_reconfigure::Reconfigure>("set_gains_out");
+     240             : 
+     241             :   // | ----------------------- subscribers ---------------------- |
+     242             : 
+     243          14 :   mrs_lib::SubscribeHandlerOptions shopts;
+     244           7 :   shopts.nh                 = nh_;
+     245           7 :   shopts.node_name          = "GainManager";
+     246           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+     247           7 :   shopts.threadsafe         = true;
+     248           7 :   shopts.autostart          = true;
+     249           7 :   shopts.queue_size         = 10;
+     250           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     251             : 
+     252           7 :   sh_estimation_diag_      = mrs_lib::SubscribeHandler<mrs_msgs::EstimationDiagnostics>(shopts, "estimation_diagnostics_in");
+     253           7 :   sh_control_manager_diag_ = mrs_lib::SubscribeHandler<mrs_msgs::ControlManagerDiagnostics>(shopts, "control_manager_diagnostics_in");
+     254             : 
+     255             :   // | ----------------------- publishers ----------------------- |
+     256             : 
+     257           7 :   ph_diagnostics_ = mrs_lib::PublisherHandler<mrs_msgs::GainManagerDiagnostics>(nh_, "diagnostics_out", 1);
+     258             : 
+     259             :   // | ------------------------- timers ------------------------- |
+     260             : 
+     261           7 :   timer_gain_management_ = nh_.createTimer(ros::Rate(_gain_management_rate_), &GainManager::timerGainManagement, this);
+     262           7 :   timer_diagnostics_     = nh_.createTimer(ros::Rate(_diagnostics_rate_), &GainManager::timerDiagnostics, this);
+     263             : 
+     264             :   // | ------------------------ profiler ------------------------ |
+     265             : 
+     266           7 :   profiler_ = mrs_lib::Profiler(nh_, "GainManager", _profiler_enabled_);
+     267             : 
+     268             :   // | ----------------------- finish init ---------------------- |
+     269             : 
+     270           7 :   if (!param_loader.loadedSuccessfully()) {
+     271           0 :     ROS_ERROR("[GainManager]: could not load all parameters!");
+     272           0 :     ros::shutdown();
+     273             :   }
+     274             : 
+     275           7 :   is_initialized_ = true;
+     276             : 
+     277           7 :   ROS_INFO("[GainManager]: initialized");
+     278             : 
+     279           7 :   ROS_DEBUG("[GainManager]: debug output is enabled");
+     280           7 : }
+     281             : 
+     282             : //}
+     283             : 
+     284             : // --------------------------------------------------------------
+     285             : // |                           methods                          |
+     286             : // --------------------------------------------------------------
+     287             : 
+     288             : /* setGains() //{ */
+     289             : 
+     290           7 : bool GainManager::setGains(std::string gains_name) {
+     291             : 
+     292           7 :   std::map<std::string, Gains_t>::iterator it;
+     293           7 :   it = _gains_.find(gains_name);
+     294             : 
+     295           7 :   if (it == _gains_.end()) {
+     296           0 :     ROS_WARN("[GainManager]: can not set gains for '%s', the mode is not on a list!", gains_name.c_str());
+     297           0 :     return false;
+     298             :   }
+     299             : 
+     300          14 :   dynamic_reconfigure::Config          conf;
+     301          14 :   dynamic_reconfigure::DoubleParameter param;
+     302             : 
+     303           7 :   param.name  = "kpxy";
+     304           7 :   param.value = it->second.kpxy;
+     305           7 :   conf.doubles.push_back(param);
+     306             : 
+     307           7 :   param.name  = "kvxy";
+     308           7 :   param.value = it->second.kvxy;
+     309           7 :   conf.doubles.push_back(param);
+     310             : 
+     311           7 :   param.name  = "kaxy";
+     312           7 :   param.value = it->second.kaxy;
+     313           7 :   conf.doubles.push_back(param);
+     314             : 
+     315           7 :   param.name  = "kq_roll_pitch";
+     316           7 :   param.value = it->second.kqrp;
+     317           7 :   conf.doubles.push_back(param);
+     318             : 
+     319           7 :   param.name  = "kibxy";
+     320           7 :   param.value = it->second.kibxy;
+     321           7 :   conf.doubles.push_back(param);
+     322             : 
+     323           7 :   param.name  = "kiwxy";
+     324           7 :   param.value = it->second.kiwxy;
+     325           7 :   conf.doubles.push_back(param);
+     326             : 
+     327           7 :   param.name  = "kibxy_lim";
+     328           7 :   param.value = it->second.kibxy_lim;
+     329           7 :   conf.doubles.push_back(param);
+     330             : 
+     331           7 :   param.name  = "kiwxy_lim";
+     332           7 :   param.value = it->second.kiwxy_lim;
+     333           7 :   conf.doubles.push_back(param);
+     334             : 
+     335           7 :   param.name  = "kpz";
+     336           7 :   param.value = it->second.kpz;
+     337           7 :   conf.doubles.push_back(param);
+     338             : 
+     339           7 :   param.name  = "kvz";
+     340           7 :   param.value = it->second.kvz;
+     341           7 :   conf.doubles.push_back(param);
+     342             : 
+     343           7 :   param.name  = "kaz";
+     344           7 :   param.value = it->second.kaz;
+     345           7 :   conf.doubles.push_back(param);
+     346             : 
+     347           7 :   param.name  = "kq_yaw";
+     348           7 :   param.value = it->second.kqy;
+     349           7 :   conf.doubles.push_back(param);
+     350             : 
+     351           7 :   param.name  = "km";
+     352           7 :   param.value = it->second.km;
+     353           7 :   conf.doubles.push_back(param);
+     354             : 
+     355           7 :   param.name  = "km_lim";
+     356           7 :   param.value = it->second.km_lim;
+     357           7 :   conf.doubles.push_back(param);
+     358             : 
+     359          14 :   dynamic_reconfigure::ReconfigureRequest  srv_req;
+     360          14 :   dynamic_reconfigure::ReconfigureResponse srv_resp;
+     361             : 
+     362           7 :   srv_req.config = conf;
+     363             : 
+     364          14 :   dynamic_reconfigure::Reconfigure reconf;
+     365           7 :   reconf.request = srv_req;
+     366             : 
+     367           7 :   ROS_INFO_THROTTLE(1.0, "[GainManager]: setting up gains for '%s'", gains_name.c_str());
+     368             : 
+     369           7 :   bool res = service_client_set_gains_.call(reconf);
+     370             : 
+     371           7 :   if (!res) {
+     372             : 
+     373           0 :     ROS_WARN_THROTTLE(1.0, "[GainManager]: the service for setting gains has failed!");
+     374           0 :     return false;
+     375             : 
+     376             :   } else {
+     377             : 
+     378           7 :     mrs_lib::set_mutexed(mutex_current_gains_, gains_name, current_gains_);
+     379             : 
+     380           7 :     return true;
+     381             :   }
+     382             : }
+     383             : 
+     384             : //}
+     385             : 
+     386             : // --------------------------------------------------------------
+     387             : // |                          callbacks                         |
+     388             : // --------------------------------------------------------------
+     389             : 
+     390             : // | -------------------- service callbacks ------------------- |
+     391             : 
+     392             : /* //{ callbackSetGains() */
+     393             : 
+     394           0 : bool GainManager::callbackSetGains(mrs_msgs::String::Request& req, mrs_msgs::String::Response& res) {
+     395             : 
+     396           0 :   if (!is_initialized_) {
+     397           0 :     return false;
+     398             :   }
+     399             : 
+     400           0 :   std::stringstream ss;
+     401             : 
+     402           0 :   if (!sh_estimation_diag_.hasMsg()) {
+     403             : 
+     404           0 :     ss << "missing estimation diagnostics";
+     405             : 
+     406           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[GainManager]: " << ss.str());
+     407             : 
+     408           0 :     res.message = ss.str();
+     409           0 :     res.success = false;
+     410           0 :     return true;
+     411             :   }
+     412             : 
+     413           0 :   auto estimation_diagnostics = *sh_estimation_diag_.getMsg();
+     414             : 
+     415           0 :   if (!stringInVector(req.value, _gain_names_)) {
+     416             : 
+     417           0 :     ss << "the gains '" << req.value.c_str() << "' do not exist (in the GainManager's config)";
+     418             : 
+     419           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[GainManager]: " << ss.str());
+     420             : 
+     421           0 :     res.message = ss.str();
+     422           0 :     res.success = false;
+     423           0 :     return true;
+     424             :   }
+     425             : 
+     426           0 :   if (!stringInVector(req.value, _map_type_allowed_gains_.at(estimation_diagnostics.current_state_estimator))) {
+     427             : 
+     428           0 :     ss << "the gains '" << req.value.c_str() << "' are not allowed given the current state estimator";
+     429             : 
+     430           0 :     ROS_WARN_STREAM_THROTTLE(1.0, "[GainManager]: " << ss.str());
+     431             : 
+     432           0 :     res.message = ss.str();
+     433           0 :     res.success = false;
+     434           0 :     return true;
+     435             :   }
+     436             : 
+     437             :   // try to set the gains
+     438           0 :   if (!setGains(req.value)) {
+     439             : 
+     440           0 :     ss << "the Se3Controller could not set the gains";
+     441             : 
+     442           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[GainManager]: " << ss.str());
+     443             : 
+     444           0 :     res.message = ss.str();
+     445           0 :     res.success = false;
+     446           0 :     return true;
+     447             : 
+     448             :   } else {
+     449             : 
+     450           0 :     ss << "the gains '" << req.value.c_str() << "' are set";
+     451             : 
+     452           0 :     ROS_INFO_STREAM_THROTTLE(1.0, "[GainManager]: " << ss.str());
+     453             : 
+     454           0 :     res.message = ss.str();
+     455           0 :     res.success = true;
+     456           0 :     return true;
+     457             :   }
+     458             : }
+     459             : 
+     460             : //}
+     461             : 
+     462             : // --------------------------------------------------------------
+     463             : // |                           timers                           |
+     464             : // --------------------------------------------------------------
+     465             : 
+     466             : /* gainManagementTimer() //{ */
+     467             : 
+     468        1190 : void GainManager::timerGainManagement(const ros::TimerEvent& event) {
+     469             : 
+     470        1190 :   if (!is_initialized_) {
+     471         296 :     return;
+     472             :   }
+     473             : 
+     474        2380 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("gainManagementTimer", _gain_management_rate_, 0.01, event);
+     475        2380 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("GainManager::gainManagementTimer", scope_timer_logger_, scope_timer_enabled_);
+     476             : 
+     477        1190 :   if (!sh_estimation_diag_.hasMsg()) {
+     478         296 :     return;
+     479             :   }
+     480             : 
+     481         894 :   auto estimation_diagnostics = *sh_estimation_diag_.getMsg();
+     482             : 
+     483         894 :   if (!sh_control_manager_diag_.hasMsg()) {
+     484           0 :     return;
+     485             :   }
+     486             : 
+     487        1788 :   auto control_manager_diagnostics = *sh_estimation_diag_.getMsg();
+     488             : 
+     489        1788 :   auto current_gains       = mrs_lib::get_mutexed(mutex_current_gains_, current_gains_);
+     490         894 :   auto last_estimator_name = mrs_lib::get_mutexed(mutex_last_estimator_name_, last_estimator_name_);
+     491             : 
+     492             :   // | --- automatically set _gains_ when currrent state estimator changes -- |
+     493         894 :   if (estimation_diagnostics.current_state_estimator != last_estimator_name) {
+     494             : 
+     495           7 :     ROS_INFO_THROTTLE(1.0, "[GainManager]: the state estimator has changed! %s -> %s", last_estimator_name_.c_str(),
+     496             :                       estimation_diagnostics.current_state_estimator.c_str());
+     497             : 
+     498           7 :     std::map<std::string, std::string>::iterator it;
+     499           7 :     it = _map_type_default_gains_.find(estimation_diagnostics.current_state_estimator);
+     500             : 
+     501           7 :     if (it == _map_type_default_gains_.end()) {
+     502             : 
+     503           0 :       ROS_WARN_THROTTLE(1.0, "[GainManager]: the state estimator '%s' was not specified in the gain_manager's config!",
+     504             :                         estimation_diagnostics.current_state_estimator.c_str());
+     505             : 
+     506             :     } else {
+     507             : 
+     508             :       // if the current gains are within the allowed estimator types, do nothing
+     509           7 :       if (stringInVector(current_gains, _map_type_allowed_gains_.at(estimation_diagnostics.current_state_estimator))) {
+     510             : 
+     511           0 :         last_estimator_name = estimation_diagnostics.current_state_estimator;
+     512             : 
+     513             :         // else, try to set the default gains
+     514             :       } else {
+     515             : 
+     516           7 :         ROS_WARN_THROTTLE(1.0, "[GainManager]: the current gains '%s' are not within the allowed gains for '%s'", current_gains.c_str(),
+     517             :                           estimation_diagnostics.current_state_estimator.c_str());
+     518             : 
+     519           7 :         if (setGains(it->second)) {
+     520             : 
+     521           7 :           last_estimator_name = estimation_diagnostics.current_state_estimator;
+     522             : 
+     523           7 :           ROS_INFO_THROTTLE(1.0, "[GainManager]: gains set to default: '%s'", it->second.c_str());
+     524             : 
+     525             :         } else {
+     526             : 
+     527           0 :           ROS_WARN_THROTTLE(1.0, "[GainManager]: could not set gains!");
+     528             :         }
+     529             :       }
+     530             :     }
+     531             :   }
+     532             : 
+     533         894 :   mrs_lib::set_mutexed(mutex_last_estimator_name_, last_estimator_name, last_estimator_name_);
+     534             : }
+     535             : 
+     536             : //}
+     537             : 
+     538             : /* dignosticsTimer() //{ */
+     539             : 
+     540         116 : void GainManager::timerDiagnostics(const ros::TimerEvent& event) {
+     541             : 
+     542         116 :   if (!is_initialized_) {
+     543          28 :     return;
+     544             :   }
+     545             : 
+     546         232 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerDiagnostics", _diagnostics_rate_, 0.01, event);
+     547         232 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("GainManager::timerDiagnostics", scope_timer_logger_, scope_timer_enabled_);
+     548             : 
+     549         116 :   if (!sh_estimation_diag_.hasMsg()) {
+     550          28 :     ROS_WARN_THROTTLE(10.0, "[GainManager]: can not do constraint management, missing estimator diagnostics!");
+     551          28 :     return;
+     552             :   }
+     553             : 
+     554          88 :   if (!sh_control_manager_diag_.hasMsg()) {
+     555           0 :     ROS_WARN_THROTTLE(10.0, "[GainManager]: can not do constraint management, missing control manager diagnostics!");
+     556           0 :     return;
+     557             :   }
+     558             : 
+     559         176 :   auto estimation_diagnostics = *sh_estimation_diag_.getMsg();
+     560             : 
+     561         176 :   auto current_gains = mrs_lib::get_mutexed(mutex_current_gains_, current_gains_);
+     562             : 
+     563         176 :   mrs_msgs::GainManagerDiagnostics diagnostics;
+     564             : 
+     565          88 :   diagnostics.stamp        = ros::Time::now();
+     566          88 :   diagnostics.current_name = current_gains;
+     567          88 :   diagnostics.loaded       = _gain_names_;
+     568             : 
+     569             :   // get the available gains
+     570             :   {
+     571          88 :     std::map<std::string, std::vector<std::string>>::iterator it;
+     572          88 :     it = _map_type_allowed_gains_.find(estimation_diagnostics.current_state_estimator);
+     573             : 
+     574          88 :     if (it == _map_type_allowed_gains_.end()) {
+     575           0 :       ROS_WARN_THROTTLE(1.0, "[GainManager]: the estimator name '%s' was not specified in the gain_manager's config!",
+     576             :                         estimation_diagnostics.current_state_estimator.c_str());
+     577             :     } else {
+     578          88 :       diagnostics.available = it->second;
+     579             :     }
+     580             :   }
+     581             : 
+     582             :   // get the current gain values
+     583             :   {
+     584          88 :     std::map<std::string, Gains_t>::iterator it;
+     585          88 :     it = _gains_.find(current_gains);
+     586             : 
+     587          88 :     diagnostics.current_values.kpxy = it->second.kpxy;
+     588          88 :     diagnostics.current_values.kvxy = it->second.kvxy;
+     589          88 :     diagnostics.current_values.kaxy = it->second.kaxy;
+     590             : 
+     591          88 :     diagnostics.current_values.kqrp = it->second.kqrp;
+     592             : 
+     593          88 :     diagnostics.current_values.kibxy     = it->second.kibxy;
+     594          88 :     diagnostics.current_values.kibxy_lim = it->second.kibxy_lim;
+     595             : 
+     596          88 :     diagnostics.current_values.kiwxy     = it->second.kiwxy;
+     597          88 :     diagnostics.current_values.kiwxy_lim = it->second.kiwxy_lim;
+     598             : 
+     599          88 :     diagnostics.current_values.kpz = it->second.kpz;
+     600          88 :     diagnostics.current_values.kvz = it->second.kvz;
+     601          88 :     diagnostics.current_values.kaz = it->second.kaz;
+     602             : 
+     603          88 :     diagnostics.current_values.kqy = it->second.kqy;
+     604             : 
+     605          88 :     diagnostics.current_values.km     = it->second.km;
+     606          88 :     diagnostics.current_values.km_lim = it->second.km_lim;
+     607             :   }
+     608             : 
+     609          88 :   ph_diagnostics_.publish(diagnostics);
+     610             : }
+     611             : 
+     612             : //}
+     613             : 
+     614             : // --------------------------------------------------------------
+     615             : // |                          routines                          |
+     616             : // --------------------------------------------------------------
+     617             : 
+     618             : /* stringInVector() //{ */
+     619             : 
+     620         154 : bool GainManager::stringInVector(const std::string& value, const std::vector<std::string>& vector) {
+     621             : 
+     622         154 :   if (std::find(vector.begin(), vector.end(), value) == vector.end()) {
+     623           7 :     return false;
+     624             :   } else {
+     625         147 :     return true;
+     626             :   }
+     627             : }
+     628             : 
+     629             : //}
+     630             : 
+     631             : }  // namespace gain_manager
+     632             : 
+     633             : }  // namespace mrs_uav_managers
+     634             : 
+     635             : #include <pluginlib/class_list_macros.h>
+     636           7 : PLUGINLIB_EXPORT_CLASS(mrs_uav_managers::gain_manager::GainManager, nodelet::Nodelet)
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/index-sort-f.html b/mrs_uav_managers/src/index-sort-f.html new file mode 100644 index 0000000000..6d642982e3 --- /dev/null +++ b/mrs_uav_managers/src/index-sort-f.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/srcHitTotalCoverage
Test:coverage.infoLines:931169055.1 %
Date:2023-11-29 14:09:54Functions:537372.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
null_tracker.cpp +
64.4%64.4%
+
64.4 %38 / 5950.0 %10 / 20
constraint_manager.cpp +
65.2%65.2%
+
65.2 %148 / 22775.0 %6 / 8
uav_manager.cpp +
47.2%47.2%
+
47.2 %543 / 115181.6 %31 / 38
gain_manager.cpp +
79.8%79.8%
+
79.8 %202 / 25385.7 %6 / 7
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/index-sort-l.html b/mrs_uav_managers/src/index-sort-l.html new file mode 100644 index 0000000000..c590cd63e0 --- /dev/null +++ b/mrs_uav_managers/src/index-sort-l.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/srcHitTotalCoverage
Test:coverage.infoLines:931169055.1 %
Date:2023-11-29 14:09:54Functions:537372.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
uav_manager.cpp +
47.2%47.2%
+
47.2 %543 / 115181.6 %31 / 38
null_tracker.cpp +
64.4%64.4%
+
64.4 %38 / 5950.0 %10 / 20
constraint_manager.cpp +
65.2%65.2%
+
65.2 %148 / 22775.0 %6 / 8
gain_manager.cpp +
79.8%79.8%
+
79.8 %202 / 25385.7 %6 / 7
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/index.html b/mrs_uav_managers/src/index.html new file mode 100644 index 0000000000..5fd31318d8 --- /dev/null +++ b/mrs_uav_managers/src/index.html @@ -0,0 +1,123 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/srcHitTotalCoverage
Test:coverage.infoLines:931169055.1 %
Date:2023-11-29 14:09:54Functions:537372.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
constraint_manager.cpp +
65.2%65.2%
+
65.2 %148 / 22775.0 %6 / 8
gain_manager.cpp +
79.8%79.8%
+
79.8 %202 / 25385.7 %6 / 7
null_tracker.cpp +
64.4%64.4%
+
64.4 %38 / 5950.0 %10 / 20
uav_manager.cpp +
47.2%47.2%
+
47.2 %543 / 115181.6 %31 / 38
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/null_tracker.cpp.func-sort-c.html b/mrs_uav_managers/src/null_tracker.cpp.func-sort-c.html new file mode 100644 index 0000000000..fb3fc0a0a1 --- /dev/null +++ b/mrs_uav_managers/src/null_tracker.cpp.func-sort-c.html @@ -0,0 +1,152 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/null_tracker.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - null_tracker.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:385964.4 %
Date:2023-11-29 14:09:54Functions:102050.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers11NullTracker11resetStaticEv0
_ZN16mrs_uav_managers11NullTracker12setReferenceERKN5boost10shared_ptrIKN8mrs_msgs20ReferenceSrvRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker19gotoTrajectoryStartERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker20setVelocityReferenceERKN5boost10shared_ptrIKN8mrs_msgs28VelocityReferenceSrvRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker20switchOdometrySourceERKN8mrs_msgs9UavState_ISaIvEEE0
_ZN16mrs_uav_managers11NullTracker22setTrajectoryReferenceERKN5boost10shared_ptrIKN8mrs_msgs30TrajectoryReferenceSrvRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker22stopTrajectoryTrackingERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker23startTrajectoryTrackingERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker24resumeTrajectoryTrackingERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker5hoverERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker15enableCallbacksERKN5boost10shared_ptrIKN8std_srvs15SetBoolRequest_ISaIvEEEEE1
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers11NullTracker10initializeERKN3ros10NodeHandleESt10shared_ptrINS_15control_manager16CommonHandlers_tEES5_INS6_17PrivateHandlers_tEE7
_ZN16mrs_uav_managers11NullTrackerD0Ev7
_ZN16mrs_uav_managers11NullTrackerD2Ev7
_ZN16mrs_uav_managers11NullTracker10deactivateEv21
_ZN16mrs_uav_managers11NullTracker8activateB5cxx11ERKSt8optionalIN8mrs_msgs15TrackerCommand_ISaIvEEEE21
_ZN16mrs_uav_managers11NullTracker14setConstraintsERKN5boost10shared_ptrIKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEEEE24
_ZN16mrs_uav_managers11NullTracker9getStatusEv351
_ZN16mrs_uav_managers11NullTracker6updateERKN8mrs_msgs9UavState_ISaIvEEERKNS_10Controller13ControlOutputE6839
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/null_tracker.cpp.func.html b/mrs_uav_managers/src/null_tracker.cpp.func.html new file mode 100644 index 0000000000..e1ea6077a3 --- /dev/null +++ b/mrs_uav_managers/src/null_tracker.cpp.func.html @@ -0,0 +1,152 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/null_tracker.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - null_tracker.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:385964.4 %
Date:2023-11-29 14:09:54Functions:102050.0 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers11NullTracker10deactivateEv21
_ZN16mrs_uav_managers11NullTracker10initializeERKN3ros10NodeHandleESt10shared_ptrINS_15control_manager16CommonHandlers_tEES5_INS6_17PrivateHandlers_tEE7
_ZN16mrs_uav_managers11NullTracker11resetStaticEv0
_ZN16mrs_uav_managers11NullTracker12setReferenceERKN5boost10shared_ptrIKN8mrs_msgs20ReferenceSrvRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker14setConstraintsERKN5boost10shared_ptrIKN8mrs_msgs30DynamicsConstraintsSrvRequest_ISaIvEEEEE24
_ZN16mrs_uav_managers11NullTracker15enableCallbacksERKN5boost10shared_ptrIKN8std_srvs15SetBoolRequest_ISaIvEEEEE1
_ZN16mrs_uav_managers11NullTracker19gotoTrajectoryStartERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker20setVelocityReferenceERKN5boost10shared_ptrIKN8mrs_msgs28VelocityReferenceSrvRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker20switchOdometrySourceERKN8mrs_msgs9UavState_ISaIvEEE0
_ZN16mrs_uav_managers11NullTracker22setTrajectoryReferenceERKN5boost10shared_ptrIKN8mrs_msgs30TrajectoryReferenceSrvRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker22stopTrajectoryTrackingERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker23startTrajectoryTrackingERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker24resumeTrajectoryTrackingERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker5hoverERKN5boost10shared_ptrIKN8std_srvs15TriggerRequest_ISaIvEEEEE0
_ZN16mrs_uav_managers11NullTracker6updateERKN8mrs_msgs9UavState_ISaIvEEERKNS_10Controller13ControlOutputE6839
_ZN16mrs_uav_managers11NullTracker8activateB5cxx11ERKSt8optionalIN8mrs_msgs15TrackerCommand_ISaIvEEEE21
_ZN16mrs_uav_managers11NullTracker9getStatusEv351
_ZN16mrs_uav_managers11NullTrackerD0Ev7
_ZN16mrs_uav_managers11NullTrackerD2Ev7
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/null_tracker.cpp.gcov.html b/mrs_uav_managers/src/null_tracker.cpp.gcov.html new file mode 100644 index 0000000000..6f9c36de26 --- /dev/null +++ b/mrs_uav_managers/src/null_tracker.cpp.gcov.html @@ -0,0 +1,324 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/null_tracker.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - null_tracker.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:385964.4 %
Date:2023-11-29 14:09:54Functions:102050.0 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : #include <ros/ros.h>
+       2             : 
+       3             : #include <mrs_uav_managers/tracker.h>
+       4             : 
+       5             : namespace mrs_uav_managers
+       6             : {
+       7             : 
+       8             : /* //{ class NullTracker */
+       9             : 
+      10             : class NullTracker : public mrs_uav_managers::Tracker {
+      11             : 
+      12             : public:
+      13          14 :   ~NullTracker(){};
+      14             : 
+      15             :   bool initialize(const ros::NodeHandle &parent_nh, std::shared_ptr<mrs_uav_managers::control_manager::CommonHandlers_t> common_handlers,
+      16             :                   std::shared_ptr<mrs_uav_managers::control_manager::PrivateHandlers_t> private_handlers);
+      17             : 
+      18             :   std::tuple<bool, std::string> activate([[maybe_unused]] const std::optional<mrs_msgs::TrackerCommand> &last_tracker_cmd);
+      19             :   void                          deactivate(void);
+      20             :   bool                          resetStatic(void);
+      21             : 
+      22             :   std::optional<mrs_msgs::TrackerCommand>   update(const mrs_msgs::UavState &uav_state, const Controller::ControlOutput &last_control_output);
+      23             :   const mrs_msgs::TrackerStatus             getStatus();
+      24             :   const std_srvs::SetBoolResponse::ConstPtr enableCallbacks(const std_srvs::SetBoolRequest::ConstPtr &cmd);
+      25             :   const std_srvs::TriggerResponse::ConstPtr switchOdometrySource(const mrs_msgs::UavState &new_uav_state);
+      26             : 
+      27             :   const mrs_msgs::ReferenceSrvResponse::ConstPtr           setReference(const mrs_msgs::ReferenceSrvRequest::ConstPtr &cmd);
+      28             :   const mrs_msgs::VelocityReferenceSrvResponse::ConstPtr   setVelocityReference(const mrs_msgs::VelocityReferenceSrvRequest::ConstPtr &cmd);
+      29             :   const mrs_msgs::TrajectoryReferenceSrvResponse::ConstPtr setTrajectoryReference(const mrs_msgs::TrajectoryReferenceSrvRequest::ConstPtr &cmd);
+      30             : 
+      31             :   const std_srvs::TriggerResponse::ConstPtr hover(const std_srvs::TriggerRequest::ConstPtr &cmd);
+      32             :   const std_srvs::TriggerResponse::ConstPtr startTrajectoryTracking(const std_srvs::TriggerRequest::ConstPtr &cmd);
+      33             :   const std_srvs::TriggerResponse::ConstPtr stopTrajectoryTracking(const std_srvs::TriggerRequest::ConstPtr &cmd);
+      34             :   const std_srvs::TriggerResponse::ConstPtr resumeTrajectoryTracking(const std_srvs::TriggerRequest::ConstPtr &cmd);
+      35             :   const std_srvs::TriggerResponse::ConstPtr gotoTrajectoryStart(const std_srvs::TriggerRequest::ConstPtr &cmd);
+      36             : 
+      37             :   const mrs_msgs::DynamicsConstraintsSrvResponse::ConstPtr setConstraints(const mrs_msgs::DynamicsConstraintsSrvRequest::ConstPtr &cmd);
+      38             : 
+      39             : private:
+      40             :   ros::NodeHandle nh_;
+      41             :   bool            is_active         = false;
+      42             :   bool            is_initialized    = false;
+      43             :   bool            callbacks_enabled = false;
+      44             : 
+      45             :   std::shared_ptr<mrs_uav_managers::control_manager::CommonHandlers_t> common_handlers;
+      46             : };
+      47             : 
+      48             : //}
+      49             : 
+      50             : // | ------------------- trackers interface ------------------- |
+      51             : 
+      52             : /* //{ initialize() */
+      53             : 
+      54           7 : bool NullTracker::initialize(const ros::NodeHandle &                                                                parent_nh,
+      55             :                              [[maybe_unused]] std::shared_ptr<mrs_uav_managers::control_manager::CommonHandlers_t>  common_handlers,
+      56             :                              [[maybe_unused]] std::shared_ptr<mrs_uav_managers::control_manager::PrivateHandlers_t> private_handlers) {
+      57             : 
+      58          14 :   ros::NodeHandle nh_(parent_nh, "null_tracker");
+      59             : 
+      60           7 :   ros::Time::waitForValid();
+      61             : 
+      62           7 :   is_initialized = true;
+      63             : 
+      64           7 :   this->common_handlers = common_handlers;
+      65             : 
+      66           7 :   ROS_INFO("[NullTracker]: initialized");
+      67             : 
+      68          14 :   return true;
+      69             : }
+      70             : 
+      71             : //}
+      72             : 
+      73             : /* //{ activate() */
+      74             : 
+      75          21 : std::tuple<bool, std::string> NullTracker::activate([[maybe_unused]] const std::optional<mrs_msgs::TrackerCommand> &last_tracker_cmd) {
+      76             : 
+      77          21 :   std::stringstream ss;
+      78          21 :   ss << "activated";
+      79             : 
+      80          21 :   ROS_INFO_STREAM("[NullTracker]: " << ss.str());
+      81          21 :   is_active = true;
+      82             : 
+      83          42 :   return std::tuple(true, ss.str());
+      84             : }
+      85             : 
+      86             : //}
+      87             : 
+      88             : /* //{ deactivate() */
+      89             : 
+      90          21 : void NullTracker::deactivate(void) {
+      91             : 
+      92          21 :   ROS_INFO("[NullTracker]: deactivated");
+      93          21 :   is_active = false;
+      94          21 : }
+      95             : 
+      96             : //}
+      97             : 
+      98             : /* //{ resetStatic() */
+      99             : 
+     100           0 : bool NullTracker::resetStatic(void) {
+     101           0 :   return false;
+     102             : }
+     103             : 
+     104             : //}
+     105             : 
+     106             : /* switchOdometrySource() //{ */
+     107             : 
+     108           0 : const std_srvs::TriggerResponse::ConstPtr NullTracker::switchOdometrySource([[maybe_unused]] const mrs_msgs::UavState &new_uav_state) {
+     109           0 :   return std_srvs::TriggerResponse::Ptr();
+     110             : }
+     111             : 
+     112             : //}
+     113             : 
+     114             : /* //{ update() */
+     115             : 
+     116        6839 : std::optional<mrs_msgs::TrackerCommand> NullTracker::update([[maybe_unused]] const mrs_msgs::UavState &       uav_state,
+     117             :                                                             [[maybe_unused]] const Controller::ControlOutput &last_control_output) {
+     118             : 
+     119        6839 :   return {};
+     120             : }
+     121             : 
+     122             : //}
+     123             : 
+     124             : /* //{ getStatus() */
+     125             : 
+     126         351 : const mrs_msgs::TrackerStatus NullTracker::getStatus() {
+     127             : 
+     128         351 :   mrs_msgs::TrackerStatus tracker_status;
+     129             : 
+     130         351 :   tracker_status.active            = is_active;
+     131         351 :   tracker_status.callbacks_enabled = callbacks_enabled;
+     132             : 
+     133         351 :   return tracker_status;
+     134             : }
+     135             : 
+     136             : //}
+     137             : 
+     138             : /* //{ enableCallbacks() */
+     139             : 
+     140           1 : const std_srvs::SetBoolResponse::ConstPtr NullTracker::enableCallbacks(const std_srvs::SetBoolRequest::ConstPtr &cmd) {
+     141             : 
+     142           2 :   std_srvs::SetBoolResponse res;
+     143             : 
+     144           1 :   std::stringstream ss;
+     145             : 
+     146           1 :   if (cmd->data != callbacks_enabled) {
+     147             : 
+     148           1 :     callbacks_enabled = cmd->data;
+     149             : 
+     150           1 :     ss << "callbacks " << (callbacks_enabled ? "enabled" : "disabled");
+     151             : 
+     152           1 :     ROS_DEBUG_STREAM("[NullTracker]: " << ss.str());
+     153             : 
+     154             :   } else {
+     155             : 
+     156           0 :     ss << "callbacks were already " << (callbacks_enabled ? "enabled" : "disabled");
+     157             :   }
+     158             : 
+     159           1 :   res.message = ss.str();
+     160           1 :   res.success = true;
+     161             : 
+     162           3 :   return std_srvs::SetBoolResponse::ConstPtr(std::make_unique<std_srvs::SetBoolResponse>(res));
+     163             : }
+     164             : 
+     165             : //}
+     166             : 
+     167             : /* //{ setReference() */
+     168             : 
+     169           0 : const mrs_msgs::ReferenceSrvResponse::ConstPtr NullTracker::setReference([[maybe_unused]] const mrs_msgs::ReferenceSrvRequest::ConstPtr &cmd) {
+     170           0 :   return mrs_msgs::ReferenceSrvResponse::Ptr();
+     171             : }
+     172             : 
+     173             : //}
+     174             : 
+     175             : /* //{ setVelocityReference() */
+     176             : 
+     177           0 : const mrs_msgs::VelocityReferenceSrvResponse::ConstPtr NullTracker::setVelocityReference([
+     178             :     [maybe_unused]] const mrs_msgs::VelocityReferenceSrvRequest::ConstPtr &cmd) {
+     179           0 :   return mrs_msgs::VelocityReferenceSrvResponse::Ptr();
+     180             : }
+     181             : 
+     182             : //}
+     183             : 
+     184             : /* //{ setTrajectoryReference() */
+     185             : 
+     186           0 : const mrs_msgs::TrajectoryReferenceSrvResponse::ConstPtr NullTracker::setTrajectoryReference([
+     187             :     [maybe_unused]] const mrs_msgs::TrajectoryReferenceSrvRequest::ConstPtr &cmd) {
+     188           0 :   return mrs_msgs::TrajectoryReferenceSrvResponse::Ptr();
+     189             : }
+     190             : 
+     191             : //}
+     192             : 
+     193             : // | --------------------- other services --------------------- |
+     194             : 
+     195             : /* //{ hover() */
+     196             : 
+     197           0 : const std_srvs::TriggerResponse::ConstPtr NullTracker::hover([[maybe_unused]] const std_srvs::TriggerRequest::ConstPtr &cmd) {
+     198           0 :   return std_srvs::TriggerResponse::Ptr();
+     199             : }
+     200             : 
+     201             : //}
+     202             : 
+     203             : /* //{ startTrajectoryTracking() */
+     204             : 
+     205           0 : const std_srvs::TriggerResponse::ConstPtr NullTracker::startTrajectoryTracking([[maybe_unused]] const std_srvs::TriggerRequest::ConstPtr &cmd) {
+     206           0 :   return std_srvs::TriggerResponse::Ptr();
+     207             : }
+     208             : 
+     209             : //}
+     210             : 
+     211             : /* //{ stopTrajectoryTracking() */
+     212             : 
+     213           0 : const std_srvs::TriggerResponse::ConstPtr NullTracker::stopTrajectoryTracking([[maybe_unused]] const std_srvs::TriggerRequest::ConstPtr &cmd) {
+     214           0 :   return std_srvs::TriggerResponse::Ptr();
+     215             : }
+     216             : 
+     217             : //}
+     218             : 
+     219             : /* //{ resumeTrajectoryTracking() */
+     220             : 
+     221           0 : const std_srvs::TriggerResponse::ConstPtr NullTracker::resumeTrajectoryTracking([[maybe_unused]] const std_srvs::TriggerRequest::ConstPtr &cmd) {
+     222           0 :   return std_srvs::TriggerResponse::Ptr();
+     223             : }
+     224             : 
+     225             : //}
+     226             : 
+     227             : /* //{ gotoTrajectoryStart() */
+     228             : 
+     229           0 : const std_srvs::TriggerResponse::ConstPtr NullTracker::gotoTrajectoryStart([[maybe_unused]] const std_srvs::TriggerRequest::ConstPtr &cmd) {
+     230           0 :   return std_srvs::TriggerResponse::Ptr();
+     231             : }
+     232             : 
+     233             : //}
+     234             : 
+     235             : /* //{ setConstraints() */
+     236             : 
+     237          24 : const mrs_msgs::DynamicsConstraintsSrvResponse::ConstPtr NullTracker::setConstraints([
+     238             :     [maybe_unused]] const mrs_msgs::DynamicsConstraintsSrvRequest::ConstPtr &cmd) {
+     239             : 
+     240          24 :   return mrs_msgs::DynamicsConstraintsSrvResponse::Ptr();
+     241             : }
+     242             : 
+     243             : //}
+     244             : 
+     245             : }  // namespace mrs_uav_managers
+     246             : 
+     247             : #include <pluginlib/class_list_macros.h>
+     248           7 : PLUGINLIB_EXPORT_CLASS(mrs_uav_managers::NullTracker, mrs_uav_managers::Tracker)
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/transform_manager/index-sort-f.html b/mrs_uav_managers/src/transform_manager/index-sort-f.html new file mode 100644 index 0000000000..fdf48b02a9 --- /dev/null +++ b/mrs_uav_managers/src/transform_manager/index-sort-f.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/transform_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/transform_managerHitTotalCoverage
Test:coverage.infoLines:27543663.1 %
Date:2023-11-29 14:09:54Functions:101376.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
transform_manager.cpp +
63.1%63.1%
+
63.1 %275 / 43676.9 %10 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/transform_manager/index-sort-l.html b/mrs_uav_managers/src/transform_manager/index-sort-l.html new file mode 100644 index 0000000000..491f7e92e8 --- /dev/null +++ b/mrs_uav_managers/src/transform_manager/index-sort-l.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/transform_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/transform_managerHitTotalCoverage
Test:coverage.infoLines:27543663.1 %
Date:2023-11-29 14:09:54Functions:101376.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
transform_manager.cpp +
63.1%63.1%
+
63.1 %275 / 43676.9 %10 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/transform_manager/index.html b/mrs_uav_managers/src/transform_manager/index.html new file mode 100644 index 0000000000..3f727c3899 --- /dev/null +++ b/mrs_uav_managers/src/transform_manager/index.html @@ -0,0 +1,93 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/transform_manager + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/transform_managerHitTotalCoverage
Test:coverage.infoLines:27543663.1 %
Date:2023-11-29 14:09:54Functions:101376.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
transform_manager.cpp +
63.1%63.1%
+
63.1 %275 / 43676.9 %10 / 13
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/transform_manager/transform_manager.cpp.func-sort-c.html b/mrs_uav_managers/src/transform_manager/transform_manager.cpp.func-sort-c.html new file mode 100644 index 0000000000..f93a84beea --- /dev/null +++ b/mrs_uav_managers/src/transform_manager/transform_manager.cpp.func-sort-c.html @@ -0,0 +1,124 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/transform_manager/transform_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/transform_manager - transform_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:27543663.1 %
Date:2023-11-29 14:09:54Functions:101376.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers17transform_manager16TransformManager14callbackRtkGpsEN5boost10shared_ptrIKN8mrs_msgs7RtkGps_ISaIvEEEEE0
_ZNK16mrs_uav_managers17transform_manager16TransformManager17transformRtkToFcuERKN13geometry_msgs12PoseStamped_ISaIvEEE0
_ZNK16mrs_uav_managers17transform_manager16TransformManager7getNameB5cxx11Ev0
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers17transform_manager16TransformManager6onInitEv7
_ZN16mrs_uav_managers17transform_manager16TransformManagerC2Ev7
_ZNK16mrs_uav_managers17transform_manager16TransformManager12getPrintNameB5cxx11Ev99
_ZN16mrs_uav_managers17transform_manager16TransformManager17callbackHeightAglEN5boost10shared_ptrIKN8mrs_msgs15Float64Stamped_ISaIvEEEEE5265
_ZN16mrs_uav_managers17transform_manager16TransformManager12callbackGnssEN5boost10shared_ptrIKN11sensor_msgs10NavSatFix_ISaIvEEEEE5816
_ZN16mrs_uav_managers17transform_manager16TransformManager16callbackUavStateEN5boost10shared_ptrIKN8mrs_msgs9UavState_ISaIvEEEEE8944
_ZN16mrs_uav_managers17transform_manager16TransformManager20callbackAltitudeAmslEN5boost10shared_ptrIKN8mrs_msgs14HwApiAltitude_ISaIvEEEEE9521
_ZN16mrs_uav_managers17transform_manager16TransformManager20publishFcuUntiltedTfERKN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE27572
_ZN16mrs_uav_managers17transform_manager16TransformManager24callbackHwApiOrientationEN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE27572
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/transform_manager/transform_manager.cpp.func.html b/mrs_uav_managers/src/transform_manager/transform_manager.cpp.func.html new file mode 100644 index 0000000000..e206dd2c76 --- /dev/null +++ b/mrs_uav_managers/src/transform_manager/transform_manager.cpp.func.html @@ -0,0 +1,124 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/transform_manager/transform_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/transform_manager - transform_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:27543663.1 %
Date:2023-11-29 14:09:54Functions:101376.9 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers17transform_manager16TransformManager12callbackGnssEN5boost10shared_ptrIKN11sensor_msgs10NavSatFix_ISaIvEEEEE5816
_ZN16mrs_uav_managers17transform_manager16TransformManager14callbackRtkGpsEN5boost10shared_ptrIKN8mrs_msgs7RtkGps_ISaIvEEEEE0
_ZN16mrs_uav_managers17transform_manager16TransformManager16callbackUavStateEN5boost10shared_ptrIKN8mrs_msgs9UavState_ISaIvEEEEE8944
_ZN16mrs_uav_managers17transform_manager16TransformManager17callbackHeightAglEN5boost10shared_ptrIKN8mrs_msgs15Float64Stamped_ISaIvEEEEE5265
_ZN16mrs_uav_managers17transform_manager16TransformManager20callbackAltitudeAmslEN5boost10shared_ptrIKN8mrs_msgs14HwApiAltitude_ISaIvEEEEE9521
_ZN16mrs_uav_managers17transform_manager16TransformManager20publishFcuUntiltedTfERKN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE27572
_ZN16mrs_uav_managers17transform_manager16TransformManager24callbackHwApiOrientationEN5boost10shared_ptrIKN13geometry_msgs18QuaternionStamped_ISaIvEEEEE27572
_ZN16mrs_uav_managers17transform_manager16TransformManager6onInitEv7
_ZN16mrs_uav_managers17transform_manager16TransformManagerC2Ev7
_ZNK16mrs_uav_managers17transform_manager16TransformManager12getPrintNameB5cxx11Ev99
_ZNK16mrs_uav_managers17transform_manager16TransformManager17transformRtkToFcuERKN13geometry_msgs12PoseStamped_ISaIvEEE0
_ZNK16mrs_uav_managers17transform_manager16TransformManager7getNameB5cxx11Ev0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/transform_manager/transform_manager.cpp.gcov.html b/mrs_uav_managers/src/transform_manager/transform_manager.cpp.gcov.html new file mode 100644 index 0000000000..3726e56ceb --- /dev/null +++ b/mrs_uav_managers/src/transform_manager/transform_manager.cpp.gcov.html @@ -0,0 +1,1022 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/transform_manager/transform_manager.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src/transform_manager - transform_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:27543663.1 %
Date:2023-11-29 14:09:54Functions:101376.9 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /* //{ includes */
+       2             : 
+       3             : #include <ros/ros.h>
+       4             : #include <nodelet/nodelet.h>
+       5             : 
+       6             : #include <mrs_lib/param_loader.h>
+       7             : #include <mrs_lib/subscribe_handler.h>
+       8             : #include <mrs_lib/publisher_handler.h>
+       9             : #include <mrs_lib/attitude_converter.h>
+      10             : #include <mrs_lib/transformer.h>
+      11             : #include <mrs_lib/transform_broadcaster.h>
+      12             : #include <mrs_lib/gps_conversions.h>
+      13             : 
+      14             : #include <mrs_msgs/UavState.h>
+      15             : #include <mrs_msgs/Float64Stamped.h>
+      16             : #include <mrs_msgs/HwApiAltitude.h>
+      17             : #include <mrs_msgs/RtkGps.h>
+      18             : 
+      19             : #include <tf2_ros/transform_broadcaster.h>
+      20             : #include <tf2_ros/static_transform_broadcaster.h>
+      21             : #include <geometry_msgs/TransformStamped.h>
+      22             : 
+      23             : #include <sensor_msgs/NavSatFix.h>
+      24             : 
+      25             : #include <nav_msgs/Odometry.h>
+      26             : 
+      27             : #include <memory>
+      28             : #include <string>
+      29             : 
+      30             : #include <mrs_uav_managers/estimation_manager/support.h>
+      31             : #include <mrs_uav_managers/estimation_manager/common_handlers.h>
+      32             : #include <transform_manager/tf_source.h>
+      33             : #include <transform_manager/tf_mapping_origin.h>
+      34             : 
+      35             : /*//}*/
+      36             : 
+      37             : namespace mrs_uav_managers
+      38             : {
+      39             : 
+      40             : namespace transform_manager
+      41             : {
+      42             : 
+      43             : /*//{ class TransformManager */
+      44             : class TransformManager : public nodelet::Nodelet {
+      45             : 
+      46             :   using Support = estimation_manager::Support;
+      47             : 
+      48             : public:
+      49           7 :   TransformManager() {
+      50           7 :     ch_ = std::make_shared<estimation_manager::CommonHandlers_t>();
+      51             : 
+      52           7 :     ch_->nodelet_name = nodelet_name_;
+      53           7 :     ch_->package_name = package_name_;
+      54           7 :   }
+      55             : 
+      56             :   void onInit();
+      57             :   bool is_initialized_ = false;
+      58             : 
+      59             :   std::string getName() const;
+      60             : 
+      61             :   std::string getPrintName() const;
+      62             : 
+      63             : private:
+      64             :   std::string _custom_config_;
+      65             :   std::string _platform_config_;
+      66             :   std::string _world_config_;
+      67             : 
+      68             :   const std::string package_name_ = "mrs_uav_managers";
+      69             :   const std::string nodelet_name_ = "TransformManager";
+      70             :   const std::string name_         = "transform_manager";
+      71             : 
+      72             :   bool publish_fcu_untilted_tf_;
+      73             : 
+      74             :   std::string ns_local_origin_parent_frame_id_;
+      75             :   std::string ns_local_origin_child_frame_id_;
+      76             :   bool        publish_local_origin_tf_;
+      77             : 
+      78             :   std::string ns_stable_origin_parent_frame_id_;
+      79             :   std::string ns_stable_origin_child_frame_id_;
+      80             :   bool        publish_stable_origin_tf_;
+      81             : 
+      82             :   std::string         ns_fixed_origin_parent_frame_id_;
+      83             :   std::string         ns_fixed_origin_child_frame_id_;
+      84             :   bool                publish_fixed_origin_tf_;
+      85             :   geometry_msgs::Pose pose_fixed_;
+      86             :   geometry_msgs::Pose pose_fixed_diff_;
+      87             : 
+      88             :   std::string ns_amsl_origin_parent_frame_id_;
+      89             :   std::string ns_amsl_origin_child_frame_id_;
+      90             :   bool        publish_amsl_origin_tf_;
+      91             : 
+      92             :   std::string          world_origin_units_;
+      93             :   geometry_msgs::Point world_origin_;
+      94             : 
+      95             :   std::vector<std::string>               tf_source_names_, estimator_names_;
+      96             :   std::vector<std::unique_ptr<TfSource>> tf_sources_;
+      97             : 
+      98             :   std::vector<std::string> utm_source_priority_list_;
+      99             :   std::string              utm_source_name_;
+     100             : 
+     101             :   std::mutex mtx_broadcast_utm_origin_;
+     102             :   std::mutex mtx_broadcast_world_origin_;
+     103             : 
+     104             :   ros::NodeHandle nh_;
+     105             : 
+     106             :   std::shared_ptr<estimation_manager::CommonHandlers_t> ch_;
+     107             : 
+     108             :   std::shared_ptr<mrs_lib::TransformBroadcaster> broadcaster_;
+     109             : 
+     110             :   std::unique_ptr<TfMappingOrigin> tf_mapping_origin_;
+     111             : 
+     112             :   void timeoutCallback(const std::string& topic, const ros::Time& last_msg);
+     113             : 
+     114             :   mrs_lib::SubscribeHandler<mrs_msgs::UavState> sh_uav_state_;
+     115             :   void                                          callbackUavState(const mrs_msgs::UavState::ConstPtr msg);
+     116             :   std::string                                   first_frame_id_;
+     117             :   std::string                                   last_frame_id_;
+     118             :   bool                                          is_first_frame_id_set_ = false;
+     119             : 
+     120             :   mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped> sh_height_agl_;
+     121             :   void                                                callbackHeightAgl(const mrs_msgs::Float64Stamped::ConstPtr msg);
+     122             : 
+     123             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiAltitude> sh_altitude_amsl_;
+     124             :   void                                               callbackAltitudeAmsl(const mrs_msgs::HwApiAltitude::ConstPtr msg);
+     125             : 
+     126             :   mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped> sh_hw_api_orientation_;
+     127             :   void                                                        callbackHwApiOrientation(const geometry_msgs::QuaternionStamped::ConstPtr msg);
+     128             : 
+     129             :   mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix> sh_gnss_;
+     130             :   void                                              callbackGnss(const sensor_msgs::NavSatFix::ConstPtr msg);
+     131             :   std::atomic<bool>                                 got_utm_offset_ = false;
+     132             : 
+     133             :   mrs_lib::SubscribeHandler<mrs_msgs::RtkGps> sh_rtk_gps_;
+     134             :   void                                        callbackRtkGps(const mrs_msgs::RtkGps::ConstPtr msg);
+     135             : 
+     136             :   std::optional<geometry_msgs::Pose> transformRtkToFcu(const geometry_msgs::PoseStamped& pose_in) const;
+     137             : 
+     138             :   void publishFcuUntiltedTf(const geometry_msgs::QuaternionStampedConstPtr& msg);
+     139             : };
+     140             : /*//}*/
+     141             : 
+     142             : 
+     143             : /*//{ onInit() */
+     144           7 : void TransformManager::onInit() {
+     145             : 
+     146           7 :   nh_ = nodelet::Nodelet::getMTPrivateNodeHandle();
+     147             : 
+     148           7 :   ros::Time::waitForValid();
+     149             : 
+     150           7 :   ROS_INFO("[%s]: initializing", getPrintName().c_str());
+     151             : 
+     152           7 :   broadcaster_ = std::make_shared<mrs_lib::TransformBroadcaster>();
+     153             : 
+     154           7 :   ch_->transformer = std::make_shared<mrs_lib::Transformer>(nh_, getPrintName());
+     155           7 :   ch_->transformer->retryLookupNewest(true);
+     156             : 
+     157          14 :   mrs_lib::ParamLoader param_loader(nh_, getPrintName());
+     158             : 
+     159           7 :   param_loader.loadParam("custom_config", _custom_config_);
+     160           7 :   param_loader.loadParam("platform_config", _platform_config_);
+     161           7 :   param_loader.loadParam("world_config", _world_config_);
+     162             : 
+     163           7 :   if (_custom_config_ != "") {
+     164           7 :     param_loader.addYamlFile(_custom_config_);
+     165             :   }
+     166             : 
+     167           7 :   if (_platform_config_ != "") {
+     168           7 :     param_loader.addYamlFile(_platform_config_);
+     169             :   }
+     170             : 
+     171           7 :   if (_world_config_ != "") {
+     172           7 :     param_loader.addYamlFile(_world_config_);
+     173             :   }
+     174             : 
+     175           7 :   param_loader.addYamlFileFromParam("private_config");
+     176           7 :   param_loader.addYamlFileFromParam("public_config");
+     177           7 :   param_loader.addYamlFileFromParam("estimators_config");
+     178             : 
+     179          14 :   const std::string yaml_prefix = "mrs_uav_managers/transform_manager/";
+     180             : 
+     181           7 :   param_loader.loadParam("uav_name", ch_->uav_name);
+     182             : 
+     183             :   /*//{ initialize scope timer */
+     184           7 :   param_loader.loadParam(yaml_prefix + "scope_timer/enabled", ch_->scope_timer.enabled);
+     185          14 :   std::string       filepath;
+     186          14 :   const std::string time_logger_filepath = ros::package::getPath(package_name_) + "/scope_timer/transform_manager_scope_timer.txt";
+     187           7 :   ch_->scope_timer.logger                = std::make_shared<mrs_lib::ScopeTimerLogger>(time_logger_filepath, ch_->scope_timer.enabled);
+     188             :   /*//}*/
+     189             : 
+     190             :   /*//{ load world_origin parameters */
+     191             : 
+     192           7 :   bool   is_origin_param_ok = true;
+     193           7 :   double world_origin_x     = 0;
+     194           7 :   double world_origin_y     = 0;
+     195             : 
+     196           7 :   param_loader.loadParam("world_origin/units", world_origin_units_);
+     197             : 
+     198           7 :   if (Support::toLowercase(world_origin_units_) == "utm") {
+     199           0 :     ROS_INFO("[%s]: Loading world origin in UTM units.", getPrintName().c_str());
+     200           0 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_x", world_origin_x);
+     201           0 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_y", world_origin_y);
+     202             : 
+     203           7 :   } else if (Support::toLowercase(world_origin_units_) == "latlon") {
+     204             :     double lat, lon;
+     205           7 :     ROS_INFO("[%s]: Loading world origin in LatLon units.", getPrintName().c_str());
+     206           7 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_x", lat);
+     207           7 :     is_origin_param_ok &= param_loader.loadParam("world_origin/origin_y", lon);
+     208           7 :     mrs_lib::UTM(lat, lon, &world_origin_x, &world_origin_y);
+     209           7 :     ROS_INFO("[%s]: Converted to UTM x: %f, y: %f.", getPrintName().c_str(), world_origin_x, world_origin_y);
+     210             : 
+     211             :   } else {
+     212           0 :     ROS_ERROR("[%s]: world_origin_units must be (\"UTM\"|\"LATLON\"). Got '%s'", getPrintName().c_str(), world_origin_units_.c_str());
+     213           0 :     ros::shutdown();
+     214             :   }
+     215             : 
+     216           7 :   world_origin_.x = world_origin_x;
+     217           7 :   world_origin_.y = world_origin_y;
+     218           7 :   world_origin_.z = 0;
+     219             : 
+     220           7 :   if (!is_origin_param_ok) {
+     221           0 :     ROS_ERROR("[%s]: Could not load all mandatory parameters from world file. Please check your world file.", getPrintName().c_str());
+     222           0 :     ros::shutdown();
+     223             :   }
+     224             :   /*//}*/
+     225             : 
+     226             :   /*//{ load local_origin parameters */
+     227          14 :   std::string local_origin_parent_frame_id;
+     228           7 :   param_loader.loadParam(yaml_prefix + "local_origin_tf/parent", local_origin_parent_frame_id);
+     229           7 :   ns_local_origin_parent_frame_id_ = ch_->uav_name + "/" + local_origin_parent_frame_id;
+     230             : 
+     231          14 :   std::string local_origin_child_frame_id;
+     232           7 :   param_loader.loadParam(yaml_prefix + "local_origin_tf/child", local_origin_child_frame_id);
+     233           7 :   ns_local_origin_child_frame_id_ = ch_->uav_name + "/" + local_origin_child_frame_id;
+     234             : 
+     235           7 :   param_loader.loadParam(yaml_prefix + "local_origin_tf/enabled", publish_local_origin_tf_);
+     236             :   /*//}*/
+     237             : 
+     238             :   /*//{ load stable_origin parameters */
+     239          14 :   std::string stable_origin_parent_frame_id;
+     240           7 :   param_loader.loadParam(yaml_prefix + "stable_origin_tf/parent", stable_origin_parent_frame_id);
+     241           7 :   ns_stable_origin_parent_frame_id_ = ch_->uav_name + "/" + stable_origin_parent_frame_id;
+     242             : 
+     243          14 :   std::string stable_origin_child_frame_id;
+     244           7 :   param_loader.loadParam(yaml_prefix + "stable_origin_tf/child", stable_origin_child_frame_id);
+     245           7 :   ns_stable_origin_child_frame_id_ = ch_->uav_name + "/" + stable_origin_child_frame_id;
+     246             : 
+     247           7 :   param_loader.loadParam(yaml_prefix + "stable_origin_tf/enabled", publish_stable_origin_tf_);
+     248             :   /*//}*/
+     249             : 
+     250             :   /*//{ load fixed_origin parameters */
+     251          14 :   std::string fixed_origin_parent_frame_id;
+     252           7 :   param_loader.loadParam(yaml_prefix + "fixed_origin_tf/parent", fixed_origin_parent_frame_id);
+     253           7 :   ns_fixed_origin_parent_frame_id_ = ch_->uav_name + "/" + fixed_origin_parent_frame_id;
+     254             : 
+     255          14 :   std::string fixed_origin_child_frame_id;
+     256           7 :   param_loader.loadParam(yaml_prefix + "fixed_origin_tf/child", fixed_origin_child_frame_id);
+     257           7 :   ns_fixed_origin_child_frame_id_ = ch_->uav_name + "/" + fixed_origin_child_frame_id;
+     258             : 
+     259           7 :   param_loader.loadParam(yaml_prefix + "fixed_origin_tf/enabled", publish_fixed_origin_tf_);
+     260             :   /*//}*/
+     261             : 
+     262             :   /*//{ load fcu_untilted parameters */
+     263          14 :   std::string fcu_frame_id;
+     264           7 :   param_loader.loadParam(yaml_prefix + "fcu_untilted_tf/parent", fcu_frame_id);
+     265           7 :   ch_->frames.fcu    = fcu_frame_id;
+     266           7 :   ch_->frames.ns_fcu = ch_->uav_name + "/" + fcu_frame_id;
+     267             : 
+     268          14 :   std::string fcu_untilted_frame_id;
+     269           7 :   param_loader.loadParam(yaml_prefix + "fcu_untilted_tf/child", fcu_untilted_frame_id);
+     270           7 :   ch_->frames.fcu_untilted    = fcu_untilted_frame_id;
+     271           7 :   ch_->frames.ns_fcu_untilted = ch_->uav_name + "/" + fcu_untilted_frame_id;
+     272             : 
+     273           7 :   param_loader.loadParam(yaml_prefix + "fcu_untilted_tf/enabled", publish_fcu_untilted_tf_);
+     274             :   /*//}*/
+     275             : 
+     276             :   /*//{ load amsl_origin parameters*/
+     277          14 :   std::string amsl_parent_frame_id, amsl_child_frame_id;
+     278           7 :   param_loader.loadParam(yaml_prefix + "altitude_amsl_tf/enabled", publish_amsl_origin_tf_);
+     279           7 :   param_loader.loadParam(yaml_prefix + "altitude_amsl_tf/parent", amsl_parent_frame_id);
+     280           7 :   param_loader.loadParam(yaml_prefix + "altitude_amsl_tf/child", amsl_child_frame_id);
+     281           7 :   ch_->frames.amsl                = amsl_child_frame_id;
+     282           7 :   ch_->frames.ns_amsl             = ch_->uav_name + "/" + amsl_child_frame_id;
+     283           7 :   ns_amsl_origin_parent_frame_id_ = ch_->uav_name + "/" + amsl_parent_frame_id;
+     284           7 :   ns_amsl_origin_child_frame_id_  = ch_->uav_name + "/" + amsl_child_frame_id;
+     285             : 
+     286             :   /*//}*/
+     287             : 
+     288           7 :   param_loader.loadParam(yaml_prefix + "rtk_antenna/frame_id", ch_->frames.rtk_antenna);
+     289           7 :   ch_->frames.ns_rtk_antenna = ch_->uav_name + "/" + ch_->frames.rtk_antenna;
+     290             : 
+     291           7 :   param_loader.loadParam("mrs_uav_managers/estimation_manager/state_estimators", estimator_names_);
+     292           7 :   param_loader.loadParam(yaml_prefix + "tf_sources", tf_source_names_);
+     293             : 
+     294           7 :   param_loader.loadParam(yaml_prefix + "utm_source_priority", utm_source_priority_list_);
+     295          31 :   for (auto utm_source : utm_source_priority_list_) {
+     296          28 :     if (Support::isStringInVector(utm_source, estimator_names_)) {
+     297           4 :       ROS_INFO("[%s]: the source for utm_origin and world origin is: %s", getPrintName().c_str(), utm_source.c_str());
+     298           4 :       utm_source_name_ = utm_source;
+     299           4 :       break;
+     300             :     }
+     301             :   }
+     302             : 
+     303             :   /*//{ initialize tf sources */
+     304           7 :   for (size_t i = 0; i < tf_source_names_.size(); i++) {
+     305             : 
+     306           0 :     const std::string tf_source_name = tf_source_names_[i];
+     307           0 :     const bool        is_utm_source  = tf_source_name == utm_source_name_;
+     308             : 
+     309           0 :     ROS_INFO("[%s]: loading tf source: %s", getPrintName().c_str(), tf_source_name.c_str());
+     310             : 
+     311           0 :     auto source_param_loader = std::make_shared<mrs_lib::ParamLoader>(nh_, "TransformManager/" + tf_source_name);
+     312             : 
+     313           0 :     if (_custom_config_ != "") {
+     314           0 :       source_param_loader->addYamlFile(_custom_config_);
+     315             :     }
+     316             : 
+     317           0 :     if (_platform_config_ != "") {
+     318           0 :       source_param_loader->addYamlFile(_platform_config_);
+     319             :     }
+     320             : 
+     321           0 :     if (_world_config_ != "") {
+     322           0 :       source_param_loader->addYamlFile(_world_config_);
+     323             :     }
+     324             : 
+     325           0 :     source_param_loader->addYamlFileFromParam("private_config");
+     326           0 :     source_param_loader->addYamlFileFromParam("public_config");
+     327           0 :     source_param_loader->addYamlFileFromParam("estimators_config");
+     328             : 
+     329           0 :     tf_sources_.push_back(std::make_unique<TfSource>(tf_source_name, nh_, source_param_loader, broadcaster_, ch_, is_utm_source));
+     330             :   }
+     331             : 
+     332             :   // additionally publish tf of all available estimators
+     333          14 :   for (int i = 0; i < int(estimator_names_.size()); i++) {
+     334             : 
+     335          14 :     const std::string estimator_name = estimator_names_[i];
+     336           7 :     const bool        is_utm_source  = estimator_name == utm_source_name_;
+     337           7 :     ROS_INFO("[%s]: loading tf source of estimator: %s", getPrintName().c_str(), estimator_name.c_str());
+     338             : 
+     339           7 :     auto estimator_param_loader = std::make_shared<mrs_lib::ParamLoader>(nh_, "TransformManager/" + estimator_name);
+     340             : 
+     341           7 :     if (_custom_config_ != "") {
+     342           7 :       estimator_param_loader->addYamlFile(_custom_config_);
+     343             :     }
+     344             : 
+     345           7 :     if (_platform_config_ != "") {
+     346           7 :       estimator_param_loader->addYamlFile(_platform_config_);
+     347             :     }
+     348             : 
+     349           7 :     if (_world_config_ != "") {
+     350           7 :       estimator_param_loader->addYamlFile(_world_config_);
+     351             :     }
+     352             : 
+     353           7 :     estimator_param_loader->addYamlFileFromParam("private_config");
+     354           7 :     estimator_param_loader->addYamlFileFromParam("public_config");
+     355           7 :     estimator_param_loader->addYamlFileFromParam("estimators_config");
+     356             : 
+     357           7 :     tf_sources_.push_back(std::make_unique<TfSource>(estimator_name, nh_, estimator_param_loader, broadcaster_, ch_, is_utm_source));
+     358             :   }
+     359             : 
+     360             :   // initialize mapping_origin tf
+     361             :   bool mapping_origin_tf_enabled;
+     362           7 :   param_loader.loadParam(yaml_prefix + "mapping_origin_tf/enabled", mapping_origin_tf_enabled, false);
+     363             : 
+     364           7 :   if (mapping_origin_tf_enabled) {
+     365             : 
+     366           0 :     auto mapping_param_loader = std::make_shared<mrs_lib::ParamLoader>(nh_, "TransformManager/mapping_origin_tf");
+     367             : 
+     368           0 :     if (_custom_config_ != "") {
+     369           0 :       mapping_param_loader->addYamlFile(_custom_config_);
+     370             :     }
+     371             : 
+     372           0 :     if (_platform_config_ != "") {
+     373           0 :       mapping_param_loader->addYamlFile(_platform_config_);
+     374             :     }
+     375             : 
+     376           0 :     if (_world_config_ != "") {
+     377           0 :       mapping_param_loader->addYamlFile(_world_config_);
+     378             :     }
+     379             : 
+     380           0 :     mapping_param_loader->addYamlFileFromParam("private_config");
+     381           0 :     mapping_param_loader->addYamlFileFromParam("public_config");
+     382           0 :     mapping_param_loader->addYamlFileFromParam("estimators_config");
+     383             : 
+     384           0 :     tf_mapping_origin_ = std::make_unique<TfMappingOrigin>(nh_, mapping_param_loader, broadcaster_, ch_);
+     385             :   }
+     386             : 
+     387             :   //}
+     388             : 
+     389             :   /*//{ initialize subscribers */
+     390          14 :   mrs_lib::SubscribeHandlerOptions shopts;
+     391           7 :   shopts.nh                 = nh_;
+     392           7 :   shopts.node_name          = getPrintName();
+     393           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+     394           7 :   shopts.threadsafe         = true;
+     395           7 :   shopts.autostart          = true;
+     396           7 :   shopts.queue_size         = 10;
+     397           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     398             : 
+     399           7 :   sh_uav_state_ = mrs_lib::SubscribeHandler<mrs_msgs::UavState>(shopts, "uav_state_in", &TransformManager::callbackUavState, this);
+     400             : 
+     401           7 :   sh_height_agl_ = mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped>(shopts, "height_agl_in", &TransformManager::callbackHeightAgl, this);
+     402             : 
+     403           7 :   sh_altitude_amsl_ = mrs_lib::SubscribeHandler<mrs_msgs::HwApiAltitude>(shopts, "altitude_amsl_in", &TransformManager::callbackAltitudeAmsl, this);
+     404             : 
+     405             :   sh_hw_api_orientation_ =
+     406           7 :       mrs_lib::SubscribeHandler<geometry_msgs::QuaternionStamped>(shopts, "orientation_in", &TransformManager::callbackHwApiOrientation, this);
+     407             : 
+     408           7 :   if (utm_source_name_ == "rtk" || utm_source_name_ == "rtk_garmin") {
+     409           0 :     sh_rtk_gps_ = mrs_lib::SubscribeHandler<mrs_msgs::RtkGps>(shopts, "rtk_gps_in", &TransformManager::callbackRtkGps, this);
+     410             :   } else {
+     411           7 :     sh_gnss_ = mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix>(shopts, "gnss_in", &TransformManager::callbackGnss, this);
+     412             :   }
+     413             :   /*//}*/
+     414             : 
+     415           7 :   if (!param_loader.loadedSuccessfully()) {
+     416           0 :     ROS_ERROR("[%s]: Could not load all non-optional parameters. Shutting down.", getPrintName().c_str());
+     417           0 :     ros::shutdown();
+     418             :   }
+     419             : 
+     420           7 :   is_initialized_ = true;
+     421           7 :   ROS_INFO("[%s]: initialized", getPrintName().c_str());
+     422           7 : }
+     423             : /*//}*/
+     424             : 
+     425             : /*//{ callbackUavState() */
+     426             : 
+     427        8944 : void TransformManager::callbackUavState(const mrs_msgs::UavState::ConstPtr msg) {
+     428             : 
+     429        8944 :   if (!is_initialized_) {
+     430           0 :     return;
+     431             :   }
+     432             : 
+     433       17888 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::publishFcuUntilted", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     434             : 
+     435             :   // obtain first frame_id
+     436        8944 :   if (!is_first_frame_id_set_) {
+     437           7 :     first_frame_id_                = msg->header.frame_id;
+     438           7 :     last_frame_id_                 = msg->header.frame_id;
+     439           7 :     pose_fixed_                    = msg->pose;
+     440           7 :     pose_fixed_diff_.orientation.w = 1;
+     441           7 :     is_first_frame_id_set_         = true;
+     442             :   }
+     443             : 
+     444        8944 :   if (publish_local_origin_tf_) {
+     445             :     /*//{ publish local_origin tf*/
+     446        8944 :     geometry_msgs::TransformStamped tf_msg;
+     447        8944 :     tf_msg.header.stamp    = msg->header.stamp;
+     448        8944 :     tf_msg.header.frame_id = ns_local_origin_parent_frame_id_;
+     449        8944 :     tf_msg.child_frame_id  = ns_local_origin_child_frame_id_;
+     450             : 
+     451             :     // transform pose to first frame_id
+     452        8944 :     geometry_msgs::PoseStamped pose;
+     453        8944 :     pose.header = msg->header;
+     454        8944 :     pose.pose   = msg->pose;
+     455             : 
+     456        8944 :     if (pose.pose.orientation.w == 0 && pose.pose.orientation.z == 0 && pose.pose.orientation.y == 0 && pose.pose.orientation.x == 0) {
+     457           0 :       ROS_WARN_ONCE("[%s]: Uninitialized quaternion detected during publishing stable_origin tf of %s. Setting w=1", getPrintName().c_str(),
+     458             :                     pose.header.frame_id.c_str());
+     459           0 :       pose.pose.orientation.w = 1.0;
+     460             :     }
+     461             : 
+     462       17888 :     auto res = ch_->transformer->transformSingle(pose, first_frame_id_.substr(0, first_frame_id_.find("_origin")) + "_local_origin");
+     463             : 
+     464        8944 :     if (res) {
+     465        8944 :       const tf2::Transform      tf       = Support::tf2FromPose(res->pose);
+     466        8944 :       const tf2::Transform      tf_inv   = tf.inverse();
+     467        8944 :       const geometry_msgs::Pose pose_inv = Support::poseFromTf2(tf_inv);
+     468        8944 :       tf_msg.transform.translation       = Support::pointToVector3(pose_inv.position);
+     469        8944 :       tf_msg.transform.rotation          = pose_inv.orientation;
+     470             : 
+     471        8944 :       if (Support::noNans(tf_msg)) {
+     472             :         try {
+     473        8944 :           broadcaster_->sendTransform(tf_msg);
+     474             :         }
+     475           0 :         catch (...) {
+     476           0 :           ROS_ERROR("exception caught ");
+     477             :         }
+     478             :       } else {
+     479           0 :         ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     480             :                           tf_msg.child_frame_id.c_str());
+     481             :       }
+     482        8944 :       ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     483             :                     tf_msg.child_frame_id.c_str());
+     484             :     } else {
+     485           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Could not transform pose to %s. Not publishing local_origin transform.", getPrintName().c_str(), first_frame_id_.c_str());
+     486           0 :       return;
+     487             :     }
+     488             :     /*//}*/
+     489             :   }
+     490             : 
+     491        8944 :   if (publish_stable_origin_tf_) {
+     492             :     /*//{ publish stable_origin tf*/
+     493        8944 :     geometry_msgs::TransformStamped tf_msg;
+     494        8944 :     tf_msg.header.stamp    = msg->header.stamp;
+     495        8944 :     tf_msg.header.frame_id = ns_stable_origin_parent_frame_id_;
+     496        8944 :     tf_msg.child_frame_id  = ns_stable_origin_child_frame_id_;
+     497             : 
+     498             :     // transform pose to first frame_id
+     499        8944 :     geometry_msgs::PoseStamped pose;
+     500        8944 :     pose.header = msg->header;
+     501        8944 :     pose.pose   = msg->pose;
+     502        8944 :     if (pose.pose.orientation.w == 0 && pose.pose.orientation.z == 0 && pose.pose.orientation.y == 0 && pose.pose.orientation.x == 0) {
+     503           0 :       ROS_WARN_ONCE("[%s]: Uninitialized quaternion detected during publishing stable_origin tf of %s. Setting w=1", getPrintName().c_str(),
+     504             :                     pose.header.frame_id.c_str());
+     505           0 :       pose.pose.orientation.w = 1.0;
+     506             :     }
+     507             : 
+     508        8944 :     auto res = ch_->transformer->transformSingle(pose, first_frame_id_);
+     509             : 
+     510        8944 :     if (res) {
+     511        8944 :       const tf2::Transform      tf       = Support::tf2FromPose(res->pose);
+     512        8944 :       const tf2::Transform      tf_inv   = tf.inverse();
+     513        8944 :       const geometry_msgs::Pose pose_inv = Support::poseFromTf2(tf_inv);
+     514        8944 :       tf_msg.transform.translation       = Support::pointToVector3(pose_inv.position);
+     515        8944 :       tf_msg.transform.rotation          = pose_inv.orientation;
+     516             : 
+     517        8944 :       if (Support::noNans(tf_msg)) {
+     518             :         try {
+     519        8944 :           broadcaster_->sendTransform(tf_msg);
+     520             :         }
+     521           0 :         catch (...) {
+     522           0 :           ROS_ERROR("exception caught ");
+     523             :         }
+     524             :       } else {
+     525           0 :         ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     526             :                           tf_msg.child_frame_id.c_str());
+     527             :       }
+     528        8944 :       ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     529             :                     tf_msg.child_frame_id.c_str());
+     530             :     } else {
+     531           0 :       ROS_ERROR_THROTTLE(1.0, "[%s]: Could not transform pose to %s. Not publishing stable_origin transform.", getPrintName().c_str(), first_frame_id_.c_str());
+     532           0 :       return;
+     533             :     }
+     534             :     /*//}*/
+     535             :   }
+     536             : 
+     537        8944 :   if (publish_fixed_origin_tf_) {
+     538             :     /*//{ publish fixed_origin tf*/
+     539        8944 :     if (msg->header.frame_id != last_frame_id_) {
+     540           0 :       ROS_WARN("[%s]: Detected estimator change from %s to %s. Updating offset for fixed origin.", getPrintName().c_str(), last_frame_id_.c_str(),
+     541             :                msg->header.frame_id.c_str());
+     542             : 
+     543           0 :       pose_fixed_diff_ = Support::getPoseDiff(msg->pose, pose_fixed_);
+     544             :     }
+     545             : 
+     546             : 
+     547        8944 :     pose_fixed_ = Support::applyPoseDiff(msg->pose, pose_fixed_diff_);
+     548             : 
+     549       17888 :     geometry_msgs::TransformStamped tf_msg;
+     550        8944 :     tf_msg.header.stamp    = msg->header.stamp;
+     551        8944 :     tf_msg.header.frame_id = ns_fixed_origin_parent_frame_id_;
+     552        8944 :     tf_msg.child_frame_id  = ns_fixed_origin_child_frame_id_;
+     553             : 
+     554        8944 :     const tf2::Transform      tf       = Support::tf2FromPose(pose_fixed_);
+     555        8944 :     const tf2::Transform      tf_inv   = tf.inverse();
+     556        8944 :     const geometry_msgs::Pose pose_inv = Support::poseFromTf2(tf_inv);
+     557        8944 :     tf_msg.transform.translation       = Support::pointToVector3(pose_inv.position);
+     558        8944 :     tf_msg.transform.rotation          = pose_inv.orientation;
+     559             : 
+     560        8944 :     if (Support::noNans(tf_msg)) {
+     561             :       try {
+     562        8944 :         broadcaster_->sendTransform(tf_msg);
+     563             :       }
+     564           0 :       catch (...) {
+     565           0 :         ROS_ERROR("exception caught ");
+     566             :       }
+     567             :     } else {
+     568           0 :       ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     569             :                         tf_msg.child_frame_id.c_str());
+     570             :     }
+     571        8944 :     ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     572             :                   tf_msg.child_frame_id.c_str());
+     573             :     /*//}*/
+     574             :   }
+     575             : 
+     576             :   /*//{ choose another source of utm and world tfs after estimator switch */
+     577        8944 :   if (msg->header.frame_id != last_frame_id_) {
+     578           0 :     const std::string last_estimator_name    = Support::frameIdToEstimatorName(last_frame_id_);
+     579           0 :     const std::string current_estimator_name = Support::frameIdToEstimatorName(msg->header.frame_id);
+     580             : 
+     581           0 :     ROS_INFO("[%s]: Detected estimator switch: %s -> %s", getPrintName().c_str(), last_estimator_name.c_str(), current_estimator_name.c_str());
+     582             : 
+     583           0 :     bool   valid_utm_source_found = false;
+     584             :     size_t potential_utm_source_index;
+     585             : 
+     586           0 :     for (size_t i = 0; i < tf_sources_.size(); i++) {
+     587             : 
+     588             :       // first check if tf source can publish utm origin and is not the switched-from estimator
+     589           0 :       if (tf_sources_.at(i)->getIsUtmBased() && tf_sources_.at(i)->getName() != last_estimator_name) {
+     590             : 
+     591           0 :         valid_utm_source_found     = true;
+     592           0 :         potential_utm_source_index = i;
+     593             : 
+     594             :         // check if switched-to estimator is utm_based, if so, use it
+     595           0 :         if (tf_sources_.at(i)->getIsUtmBased() && tf_sources_.at(i)->getName() == current_estimator_name) {
+     596           0 :           potential_utm_source_index = i;
+     597           0 :           break;
+     598             :         }
+     599             :       }
+     600             :     }
+     601             : 
+     602             : 
+     603             :     // if we found a valid utm source, use it, otherwise stay with the switched-from estimator
+     604           0 :     if (valid_utm_source_found) {
+     605             : 
+     606             :       // stop all estimators from publishing utm source
+     607           0 :       for (size_t i = 0; i < tf_sources_.size(); i++) {
+     608           0 :         if (tf_sources_.at(i)->getIsUtmSource()) {
+     609           0 :           tf_sources_.at(i)->setIsUtmSource(false);
+     610           0 :           ROS_INFO("[%s]: setting is_utm_source of estimator %s to false", getPrintName().c_str(), last_estimator_name.c_str());
+     611             :         }
+     612             :       }
+     613             : 
+     614           0 :       tf_sources_.at(potential_utm_source_index)->setIsUtmSource(true);
+     615           0 :       ROS_INFO("[%s]: setting is_utm_source of estimator %s to true", getPrintName().c_str(), current_estimator_name.c_str());
+     616             :     }
+     617             :   }
+     618             :   /*//}*/
+     619             : 
+     620        8944 :   last_frame_id_ = msg->header.frame_id;
+     621             : }
+     622             : /*//}*/
+     623             : 
+     624             : /*//{ callbackHeightAgl() */
+     625             : 
+     626        5265 : void TransformManager::callbackHeightAgl(const mrs_msgs::Float64Stamped::ConstPtr msg) {
+     627             : 
+     628        5265 :   if (!is_initialized_) {
+     629           0 :     return;
+     630             :   }
+     631             : 
+     632       15795 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::callbackHeightAgl", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     633             : 
+     634       10530 :   geometry_msgs::TransformStamped tf_msg;
+     635        5265 :   tf_msg.header.stamp    = msg->header.stamp;
+     636        5265 :   tf_msg.header.frame_id = ch_->frames.ns_fcu_untilted;
+     637        5265 :   tf_msg.child_frame_id  = msg->header.frame_id;
+     638             : 
+     639        5265 :   tf_msg.transform.translation.x = 0;
+     640        5265 :   tf_msg.transform.translation.y = 0;
+     641        5265 :   tf_msg.transform.translation.z = -msg->value;
+     642        5265 :   tf_msg.transform.rotation.x    = 0;
+     643        5265 :   tf_msg.transform.rotation.y    = 0;
+     644        5265 :   tf_msg.transform.rotation.z    = 0;
+     645        5265 :   tf_msg.transform.rotation.w    = 1;
+     646             : 
+     647        5265 :   if (Support::noNans(tf_msg)) {
+     648             :     try {
+     649        5265 :       broadcaster_->sendTransform(tf_msg);
+     650             :     }
+     651           0 :     catch (...) {
+     652           0 :       ROS_ERROR("exception caught ");
+     653             :     }
+     654             :   } else {
+     655           0 :     ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     656             :                       tf_msg.child_frame_id.c_str());
+     657             :   }
+     658        5265 :   ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     659             :                 tf_msg.child_frame_id.c_str());
+     660             : }
+     661             : /*//}*/
+     662             : 
+     663             : /*//{ callbackAltitudeAmsl() */
+     664             : 
+     665        9521 : void TransformManager::callbackAltitudeAmsl(const mrs_msgs::HwApiAltitude::ConstPtr msg) {
+     666             : 
+     667        9521 :   if (!is_initialized_) {
+     668           0 :     return;
+     669             :   }
+     670             : 
+     671       28563 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::callbackAltitudeAmsl", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     672             : 
+     673       19042 :   geometry_msgs::TransformStamped tf_msg;
+     674        9521 :   tf_msg.header.stamp    = msg->stamp;
+     675        9521 :   tf_msg.header.frame_id = ch_->frames.ns_fcu_untilted;
+     676        9521 :   tf_msg.child_frame_id  = ch_->frames.ns_amsl;
+     677             : 
+     678        9521 :   tf_msg.transform.translation.x = 0;
+     679        9521 :   tf_msg.transform.translation.y = 0;
+     680        9521 :   tf_msg.transform.translation.z = -msg->amsl;
+     681        9521 :   tf_msg.transform.rotation.x    = 0;
+     682        9521 :   tf_msg.transform.rotation.y    = 0;
+     683        9521 :   tf_msg.transform.rotation.z    = 0;
+     684        9521 :   tf_msg.transform.rotation.w    = 1;
+     685             : 
+     686        9521 :   if (Support::noNans(tf_msg)) {
+     687             :     try {
+     688        9521 :       broadcaster_->sendTransform(tf_msg);
+     689             :     }
+     690           0 :     catch (...) {
+     691           0 :       ROS_ERROR("exception caught ");
+     692             :     }
+     693             :   } else {
+     694           0 :     ROS_WARN_THROTTLE(1.0, "[%s]: NaN detected in transform from %s to %s. Not publishing tf.", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     695             :                       tf_msg.child_frame_id.c_str());
+     696             :   }
+     697        9521 :   ROS_INFO_ONCE("[%s]: Broadcasting transform from parent frame: %s to child frame: %s", getPrintName().c_str(), tf_msg.header.frame_id.c_str(),
+     698             :                 tf_msg.child_frame_id.c_str());
+     699             : }
+     700             : /*//}*/
+     701             : 
+     702             : /*//{ callbackHwApiOrientation() */
+     703       27572 : void TransformManager::callbackHwApiOrientation(const geometry_msgs::QuaternionStamped::ConstPtr msg) {
+     704             : 
+     705       27572 :   if (!is_initialized_) {
+     706           0 :     return;
+     707             :   }
+     708             : 
+     709       82716 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::publishFcuUntilted", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     710             : 
+     711       27572 :   if (publish_fcu_untilted_tf_) {
+     712       27572 :     publishFcuUntiltedTf(msg);
+     713             :   }
+     714             : }
+     715             : /*//}*/
+     716             : 
+     717             : /*//{ callbackGnss() */
+     718        5816 : void TransformManager::callbackGnss(const sensor_msgs::NavSatFix::ConstPtr msg) {
+     719             : 
+     720        5816 :   if (!is_initialized_) {
+     721        5809 :     return;
+     722             :   }
+     723             : 
+     724        5816 :   if (got_utm_offset_) {
+     725        5809 :     return;
+     726             :   }
+     727             : 
+     728          14 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::callbackGnss", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     729             : 
+     730             :   double out_x;
+     731             :   double out_y;
+     732             : 
+     733           7 :   mrs_lib::UTM(msg->latitude, msg->longitude, &out_x, &out_y);
+     734             : 
+     735           7 :   if (!std::isfinite(out_x)) {
+     736           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_x\"!!!", getPrintName().c_str());
+     737           0 :     return;
+     738             :   }
+     739             : 
+     740           7 :   if (!std::isfinite(out_y)) {
+     741           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_y\"!!!", getPrintName().c_str());
+     742           0 :     return;
+     743             :   }
+     744             : 
+     745           7 :   geometry_msgs::Point utm_origin;
+     746           7 :   utm_origin.x = out_x;
+     747           7 :   utm_origin.y = out_y;
+     748           7 :   utm_origin.z = msg->altitude;
+     749             : 
+     750           7 :   ROS_INFO("[%s]: utm_origin position calculated as: x: %.2f, y: %.2f, z: %.2f from GNSS", getPrintName().c_str(), utm_origin.x, utm_origin.y, utm_origin.z);
+     751             : 
+     752          14 :   for (size_t i = 0; i < tf_sources_.size(); i++) {
+     753           7 :     tf_sources_[i]->setUtmOrigin(utm_origin);
+     754           7 :     tf_sources_[i]->setWorldOrigin(world_origin_);
+     755             :   }
+     756           7 :   got_utm_offset_ = true;
+     757             : }
+     758             : /*//}*/
+     759             : 
+     760             : /*//{ callbackRtkGps() */
+     761           0 : void TransformManager::callbackRtkGps(const mrs_msgs::RtkGps::ConstPtr msg) {
+     762             : 
+     763           0 :   if (!is_initialized_) {
+     764           0 :     return;
+     765             :   }
+     766             : 
+     767           0 :   if (got_utm_offset_) {
+     768           0 :     return;
+     769             :   }
+     770             : 
+     771           0 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::callbackRtkGps", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     772             : 
+     773             :   double out_x;
+     774             :   double out_y;
+     775             : 
+     776           0 :   geometry_msgs::PoseStamped rtk_pos;
+     777             : 
+     778           0 :   if (!std::isfinite(msg->gps.latitude)) {
+     779           0 :     ROS_ERROR_THROTTLE(1.0, "[%s] NaN detected in RTK variable \"msg->latitude\"!!!", getPrintName().c_str());
+     780           0 :     return;
+     781             :   }
+     782             : 
+     783           0 :   if (!std::isfinite(msg->gps.longitude)) {
+     784           0 :     ROS_ERROR_THROTTLE(1.0, "[%s] NaN detected in RTK variable \"msg->longitude\"!!!", getPrintName().c_str());
+     785           0 :     return;
+     786             :   }
+     787             : 
+     788           0 :   if (!std::isfinite(msg->gps.altitude)) {
+     789           0 :     ROS_ERROR_THROTTLE(1.0, "[%s] NaN detected in RTK variable \"msg->altitude\"!!!", getPrintName().c_str());
+     790           0 :     return;
+     791             :   }
+     792             : 
+     793           0 :   if (msg->fix_type.fix_type != mrs_msgs::RtkFixType::RTK_FIX) {
+     794           0 :     ROS_INFO_THROTTLE(1.0, "[%s] %s RTK FIX", getPrintName().c_str(), Support::waiting_for_string.c_str());
+     795           0 :     return;
+     796             :   }
+     797             : 
+     798           0 :   rtk_pos.header = msg->header;
+     799           0 :   mrs_lib::UTM(msg->gps.latitude, msg->gps.longitude, &rtk_pos.pose.position.x, &rtk_pos.pose.position.y);
+     800           0 :   rtk_pos.pose.position.z  = msg->gps.altitude;
+     801           0 :   rtk_pos.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+     802             : 
+     803           0 :   rtk_pos.pose.position.x -= ch_->world_origin.x;
+     804           0 :   rtk_pos.pose.position.y -= ch_->world_origin.y;
+     805             : 
+     806             : 
+     807             :   // transform the RTK position from antenna to FCU
+     808           0 :   auto res = transformRtkToFcu(rtk_pos);
+     809           0 :   if (res) {
+     810           0 :     rtk_pos.pose = res.value();
+     811             :   } else {
+     812           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: transform to fcu failed", getPrintName().c_str());
+     813           0 :     return;
+     814             :   }
+     815             : 
+     816           0 :   mrs_lib::UTM(msg->gps.latitude, msg->gps.longitude, &out_x, &out_y);
+     817             : 
+     818           0 :   if (!std::isfinite(out_x)) {
+     819           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_x\"!!!", getPrintName().c_str());
+     820           0 :     return;
+     821             :   }
+     822             : 
+     823           0 :   if (!std::isfinite(out_y)) {
+     824           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN detected in UTM variable \"out_y\"!!!", getPrintName().c_str());
+     825           0 :     return;
+     826             :   }
+     827             : 
+     828           0 :   geometry_msgs::Point utm_origin;
+     829           0 :   utm_origin.x = out_x;
+     830           0 :   utm_origin.y = out_y;
+     831           0 :   utm_origin.z = msg->gps.altitude;
+     832             : 
+     833           0 :   ROS_INFO("[%s]: utm_origin position calculated as: x: %.2f, y: %.2f, z: %.2f from RTK msg", getPrintName().c_str(), utm_origin.x, utm_origin.y, utm_origin.z);
+     834             : 
+     835           0 :   for (size_t i = 0; i < tf_sources_.size(); i++) {
+     836           0 :     tf_sources_[i]->setUtmOrigin(utm_origin);
+     837           0 :     tf_sources_[i]->setWorldOrigin(world_origin_);
+     838             :   }
+     839           0 :   got_utm_offset_ = true;
+     840             : }
+     841             : /*//}*/
+     842             : 
+     843             : /*//{ publishFcuUntiltedTf() */
+     844       27572 : void TransformManager::publishFcuUntiltedTf(const geometry_msgs::QuaternionStampedConstPtr& msg) {
+     845             : 
+     846       55144 :   mrs_lib::ScopeTimer scope_timer = mrs_lib::ScopeTimer("TransformManager::publishFcuUntilted", ch_->scope_timer.logger, ch_->scope_timer.enabled);
+     847             : 
+     848             :   double heading;
+     849             : 
+     850             :   try {
+     851       27572 :     heading = mrs_lib::AttitudeConverter(msg->quaternion).getHeading();
+     852             :   }
+     853           0 :   catch (...) {
+     854           0 :     ROS_ERROR("[%s]: Exception caught during getting heading", getPrintName().c_str());
+     855           0 :     return;
+     856             :   }
+     857       27572 :   scope_timer.checkpoint("heading");
+     858             : 
+     859       27572 :   const Eigen::Matrix3d odom_pixhawk_R = mrs_lib::AttitudeConverter(msg->quaternion);
+     860       27572 :   const Eigen::Matrix3d undo_heading_R = mrs_lib::AttitudeConverter(Eigen::AngleAxis(-heading, Eigen::Vector3d(0, 0, 1)));
+     861             : 
+     862       27572 :   const tf2::Quaternion q     = mrs_lib::AttitudeConverter(undo_heading_R * odom_pixhawk_R);
+     863       27572 :   const tf2::Quaternion q_inv = q.inverse();
+     864             : 
+     865       27572 :   scope_timer.checkpoint("q inverse");
+     866             : 
+     867       27572 :   geometry_msgs::TransformStamped tf;
+     868       27572 :   tf.header.stamp            = msg->header.stamp;  // TODO(petrlmat) ros::Time::now()?
+     869       27572 :   tf.header.frame_id         = ch_->frames.ns_fcu;
+     870       27572 :   tf.child_frame_id          = ch_->frames.ns_fcu_untilted;
+     871       27572 :   tf.transform.translation.x = 0.0;
+     872       27572 :   tf.transform.translation.y = 0.0;
+     873       27572 :   tf.transform.translation.z = 0.0;
+     874       27572 :   tf.transform.rotation      = mrs_lib::AttitudeConverter(q_inv);
+     875             : 
+     876       27572 :   scope_timer.checkpoint("tf fill");
+     877       27572 :   if (Support::noNans(tf)) {
+     878       27572 :     broadcaster_->sendTransform(tf);
+     879             :   } else {
+     880           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: NaN encountered in fcu_untilted tf", getPrintName().c_str());
+     881             :   }
+     882       27572 :   scope_timer.checkpoint("tf pub");
+     883             : }
+     884             : /*//}*/
+     885             : 
+     886             : /*//{ transformRtkToFcu() */
+     887           0 : std::optional<geometry_msgs::Pose> TransformManager::transformRtkToFcu(const geometry_msgs::PoseStamped& pose_in) const {
+     888             : 
+     889           0 :   geometry_msgs::PoseStamped pose_tmp = pose_in;
+     890             : 
+     891             :   // inject current orientation into rtk pose
+     892           0 :   auto res1 = ch_->transformer->getTransform(ch_->frames.ns_fcu_untilted, ch_->frames.ns_fcu, ros::Time::now());
+     893           0 :   if (res1) {
+     894           0 :     pose_tmp.pose.orientation = res1.value().transform.rotation;
+     895             :   } else {
+     896           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: Could not obtain transform from %s to %s.", getPrintName().c_str(),
+     897             :                        ch_->frames.ns_fcu_untilted.c_str(), ch_->frames.ns_fcu.c_str());
+     898           0 :     return {};
+     899             :   }
+     900             : 
+     901             :   // invert tf
+     902           0 :   tf2::Transform             tf_utm_to_antenna = Support::tf2FromPose(pose_tmp.pose);
+     903           0 :   geometry_msgs::PoseStamped utm_in_antenna;
+     904           0 :   utm_in_antenna.pose            = Support::poseFromTf2(tf_utm_to_antenna.inverse());
+     905           0 :   utm_in_antenna.header.stamp    = pose_in.header.stamp;
+     906           0 :   utm_in_antenna.header.frame_id = ch_->frames.ns_rtk_antenna;
+     907             : 
+     908             :   // transform to fcu
+     909           0 :   geometry_msgs::PoseStamped utm_in_fcu;
+     910           0 :   utm_in_fcu.header.frame_id = ch_->frames.ns_fcu;
+     911           0 :   utm_in_fcu.header.stamp    = pose_in.header.stamp;
+     912           0 :   auto res2                  = ch_->transformer->transformSingle(utm_in_antenna, ch_->frames.ns_fcu);
+     913             : 
+     914           0 :   if (res2) {
+     915           0 :     utm_in_fcu = res2.value();
+     916             :   } else {
+     917           0 :     ROS_ERROR_THROTTLE(1.0, "[%s]: Could not transform RTK pose from %s to %s.", getPrintName().c_str(), utm_in_antenna.header.frame_id.c_str(), ch_->frames.ns_fcu.c_str());
+     918           0 :     return {};
+     919             :   }
+     920             : 
+     921             :   // invert tf
+     922           0 :   tf2::Transform      tf_fcu_to_utm = Support::tf2FromPose(utm_in_fcu.pose);
+     923           0 :   geometry_msgs::Pose fcu_in_utm    = Support::poseFromTf2(tf_fcu_to_utm.inverse());
+     924             : 
+     925           0 :   return fcu_in_utm;
+     926             : }
+     927             : /*//}*/
+     928             : 
+     929             : /*//{ getName() */
+     930           0 : std::string TransformManager::getName() const {
+     931           0 :   return name_;
+     932             : }
+     933             : /*//}*/
+     934             : 
+     935             : /*//{ getPrintName() */
+     936          99 : std::string TransformManager::getPrintName() const {
+     937          99 :   return nodelet_name_;
+     938             : }
+     939             : /*//}*/
+     940             : 
+     941             : }  // namespace transform_manager
+     942             : 
+     943             : }  // namespace mrs_uav_managers
+     944             : 
+     945             : #include <pluginlib/class_list_macros.h>
+     946           7 : PLUGINLIB_EXPORT_CLASS(mrs_uav_managers::transform_manager::TransformManager, nodelet::Nodelet)
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/uav_manager.cpp.func-sort-c.html b/mrs_uav_managers/src/uav_manager.cpp.func-sort-c.html new file mode 100644 index 0000000000..b81bf0bf0f --- /dev/null +++ b/mrs_uav_managers/src/uav_manager.cpp.func-sort-c.html @@ -0,0 +1,224 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/uav_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - uav_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:543115147.2 %
Date:2023-11-29 14:09:54Functions:313881.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN16mrs_uav_managers11uav_manager10UavManager12pirouetteSrvEv0
_ZN16mrs_uav_managers11uav_manager10UavManager16callbackLandHomeERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers11uav_manager10UavManager17callbackLandThereERN8mrs_msgs27ReferenceStampedSrvRequest_ISaIvEEERNS2_28ReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers11uav_manager10UavManager21emergencyReferenceSrvERKN8mrs_msgs17ReferenceStamped_ISaIvEEE0
_ZN16mrs_uav_managers11uav_manager10UavManager8elandSrvEv0
_ZN16mrs_uav_managers11uav_manager10UavManager9ehoverSrvEv0
_ZN16mrs_uav_managers11uav_manager10UavManager9ungripSrvEv0
_ZN16mrs_uav_managers11uav_manager10UavManager10takeoffSrvEv1
_ZN16mrs_uav_managers11uav_manager10UavManager12callbackLandERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE1
_ZN16mrs_uav_managers11uav_manager10UavManager15callbackTakeoffERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE1
_ZN16mrs_uav_managers11uav_manager10UavManager19landWithDescendImplB5cxx11Ev1
_ZN16mrs_uav_managers11uav_manager10UavManager22setControlCallbacksSrvERKb1
_ZN16mrs_uav_managers11uav_manager10UavManager7landSrvEv1
_ZN16mrs_uav_managers11uav_manager10UavManager8landImplB5cxx11Ev1
_ZN16mrs_uav_managers11uav_manager10UavManager9disarmSrvEv1
_ZN16mrs_uav_managers11uav_manager10UavManager18changeLandingStateENS0_15LandingStates_tE2
_ZN16mrs_uav_managers11uav_manager10UavManager15timerFlightTimeERKN3ros10TimerEventE5
_ZN16mrs_uav_managers11uav_manager10UavManager11offboardSrvEb6
_ZN16mrs_uav_managers11uav_manager10UavManager19toggleControlOutputERKb6
_ZN16mrs_uav_managers11uav_manager10UavManager20midairActivationImplB5cxx11Ev6
_ZN16mrs_uav_managers11uav_manager10UavManager21timerMidairActivationERKN3ros10TimerEventE6
_ZN16mrs_uav_managers11uav_manager10UavManager24callbackMidairActivationERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE6
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers11uav_manager10UavManager10initializeEv7
_ZN16mrs_uav_managers11uav_manager10UavManager13preinitializeEv7
_ZN16mrs_uav_managers11uav_manager10UavManager22timerHwApiCapabilitiesERKN3ros10TimerEventE7
_ZN16mrs_uav_managers11uav_manager10UavManager6onInitEv7
_ZN16mrs_uav_managers11uav_manager10UavManager23setOdometryCallbacksSrvERKb9
_ZN16mrs_uav_managers11uav_manager10UavManager19switchControllerSrvERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE15
_ZN16mrs_uav_managers11uav_manager10UavManager16switchTrackerSrvERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE16
_ZN16mrs_uav_managers11uav_manager10UavManager12timerTakeoffERKN3ros10TimerEventE48
_ZN16mrs_uav_managers11uav_manager10UavManager12timerLandingERKN3ros10TimerEventE83
_ZN16mrs_uav_managers11uav_manager10UavManager16timerDiagnosticsERKN3ros10TimerEventE108
_ZN16mrs_uav_managers11uav_manager10UavManager14timerMaxHeightERKN3ros10TimerEventE1117
_ZN16mrs_uav_managers11uav_manager10UavManager14timerMinHeightERKN3ros10TimerEventE1117
_ZN16mrs_uav_managers11uav_manager10UavManager16timerMaxthrottleERKN3ros10TimerEventE3357
_ZN16mrs_uav_managers11uav_manager10UavManager17callbackHwApiGNSSEN5boost10shared_ptrIKN11sensor_msgs10NavSatFix_ISaIvEEEEE5497
_ZN16mrs_uav_managers11uav_manager10UavManager16callbackOdometryEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE8944
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/uav_manager.cpp.func.html b/mrs_uav_managers/src/uav_manager.cpp.func.html new file mode 100644 index 0000000000..9c9123a0ee --- /dev/null +++ b/mrs_uav_managers/src/uav_manager.cpp.func.html @@ -0,0 +1,224 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/uav_manager.cpp - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - uav_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:543115147.2 %
Date:2023-11-29 14:09:54Functions:313881.6 %
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
_ZN12_GLOBAL__N_110ProxyExec0C2Ev7
_ZN16mrs_uav_managers11uav_manager10UavManager10initializeEv7
_ZN16mrs_uav_managers11uav_manager10UavManager10takeoffSrvEv1
_ZN16mrs_uav_managers11uav_manager10UavManager11offboardSrvEb6
_ZN16mrs_uav_managers11uav_manager10UavManager12callbackLandERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE1
_ZN16mrs_uav_managers11uav_manager10UavManager12pirouetteSrvEv0
_ZN16mrs_uav_managers11uav_manager10UavManager12timerLandingERKN3ros10TimerEventE83
_ZN16mrs_uav_managers11uav_manager10UavManager12timerTakeoffERKN3ros10TimerEventE48
_ZN16mrs_uav_managers11uav_manager10UavManager13preinitializeEv7
_ZN16mrs_uav_managers11uav_manager10UavManager14timerMaxHeightERKN3ros10TimerEventE1117
_ZN16mrs_uav_managers11uav_manager10UavManager14timerMinHeightERKN3ros10TimerEventE1117
_ZN16mrs_uav_managers11uav_manager10UavManager15callbackTakeoffERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE1
_ZN16mrs_uav_managers11uav_manager10UavManager15timerFlightTimeERKN3ros10TimerEventE5
_ZN16mrs_uav_managers11uav_manager10UavManager16callbackLandHomeERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE0
_ZN16mrs_uav_managers11uav_manager10UavManager16callbackOdometryEN5boost10shared_ptrIKN8nav_msgs9Odometry_ISaIvEEEEE8944
_ZN16mrs_uav_managers11uav_manager10UavManager16switchTrackerSrvERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE16
_ZN16mrs_uav_managers11uav_manager10UavManager16timerDiagnosticsERKN3ros10TimerEventE108
_ZN16mrs_uav_managers11uav_manager10UavManager16timerMaxthrottleERKN3ros10TimerEventE3357
_ZN16mrs_uav_managers11uav_manager10UavManager17callbackHwApiGNSSEN5boost10shared_ptrIKN11sensor_msgs10NavSatFix_ISaIvEEEEE5497
_ZN16mrs_uav_managers11uav_manager10UavManager17callbackLandThereERN8mrs_msgs27ReferenceStampedSrvRequest_ISaIvEEERNS2_28ReferenceStampedSrvResponse_IS4_EE0
_ZN16mrs_uav_managers11uav_manager10UavManager18changeLandingStateENS0_15LandingStates_tE2
_ZN16mrs_uav_managers11uav_manager10UavManager19landWithDescendImplB5cxx11Ev1
_ZN16mrs_uav_managers11uav_manager10UavManager19switchControllerSrvERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE15
_ZN16mrs_uav_managers11uav_manager10UavManager19toggleControlOutputERKb6
_ZN16mrs_uav_managers11uav_manager10UavManager20midairActivationImplB5cxx11Ev6
_ZN16mrs_uav_managers11uav_manager10UavManager21emergencyReferenceSrvERKN8mrs_msgs17ReferenceStamped_ISaIvEEE0
_ZN16mrs_uav_managers11uav_manager10UavManager21timerMidairActivationERKN3ros10TimerEventE6
_ZN16mrs_uav_managers11uav_manager10UavManager22setControlCallbacksSrvERKb1
_ZN16mrs_uav_managers11uav_manager10UavManager22timerHwApiCapabilitiesERKN3ros10TimerEventE7
_ZN16mrs_uav_managers11uav_manager10UavManager23setOdometryCallbacksSrvERKb9
_ZN16mrs_uav_managers11uav_manager10UavManager24callbackMidairActivationERN8std_srvs15TriggerRequest_ISaIvEEERNS2_16TriggerResponse_IS4_EE6
_ZN16mrs_uav_managers11uav_manager10UavManager6onInitEv7
_ZN16mrs_uav_managers11uav_manager10UavManager7landSrvEv1
_ZN16mrs_uav_managers11uav_manager10UavManager8elandSrvEv0
_ZN16mrs_uav_managers11uav_manager10UavManager8landImplB5cxx11Ev1
_ZN16mrs_uav_managers11uav_manager10UavManager9disarmSrvEv1
_ZN16mrs_uav_managers11uav_manager10UavManager9ehoverSrvEv0
_ZN16mrs_uav_managers11uav_manager10UavManager9ungripSrvEv0
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/mrs_uav_managers/src/uav_manager.cpp.gcov.html b/mrs_uav_managers/src/uav_manager.cpp.gcov.html new file mode 100644 index 0000000000..b37e87d3fe --- /dev/null +++ b/mrs_uav_managers/src/uav_manager.cpp.gcov.html @@ -0,0 +1,2724 @@ + + + + + + + LCOV - coverage.info - mrs_uav_managers/src/uav_manager.cpp + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - mrs_uav_managers/src - uav_manager.cpp (source / functions)HitTotalCoverage
Test:coverage.infoLines:543115147.2 %
Date:2023-11-29 14:09:54Functions:313881.6 %
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : /* includes //{ */
+       2             : 
+       3             : #include <ros/ros.h>
+       4             : #include <nodelet/nodelet.h>
+       5             : 
+       6             : #include <std_srvs/SetBool.h>
+       7             : #include <std_srvs/Trigger.h>
+       8             : #include <std_msgs/String.h>
+       9             : #include <std_msgs/Float64.h>
+      10             : 
+      11             : #include <geometry_msgs/Vector3Stamped.h>
+      12             : 
+      13             : #include <nav_msgs/Odometry.h>
+      14             : #include <mrs_msgs/Vec1.h>
+      15             : #include <mrs_msgs/Vec4.h>
+      16             : #include <mrs_msgs/String.h>
+      17             : #include <mrs_msgs/TrackerCommand.h>
+      18             : #include <mrs_msgs/Float64Stamped.h>
+      19             : #include <mrs_msgs/Float64.h>
+      20             : #include <mrs_msgs/BoolStamped.h>
+      21             : #include <mrs_msgs/ControlManagerDiagnostics.h>
+      22             : #include <mrs_msgs/ReferenceStampedSrv.h>
+      23             : #include <mrs_msgs/ConstraintManagerDiagnostics.h>
+      24             : #include <mrs_msgs/GainManagerDiagnostics.h>
+      25             : #include <mrs_msgs/UavManagerDiagnostics.h>
+      26             : #include <mrs_msgs/EstimationDiagnostics.h>
+      27             : #include <mrs_msgs/HwApiStatus.h>
+      28             : #include <mrs_msgs/ControllerDiagnostics.h>
+      29             : #include <mrs_msgs/HwApiCapabilities.h>
+      30             : 
+      31             : #include <sensor_msgs/NavSatFix.h>
+      32             : 
+      33             : #include <mrs_lib/profiler.h>
+      34             : #include <mrs_lib/scope_timer.h>
+      35             : #include <mrs_lib/param_loader.h>
+      36             : #include <mrs_lib/mutex.h>
+      37             : #include <mrs_lib/transformer.h>
+      38             : #include <mrs_lib/attitude_converter.h>
+      39             : #include <mrs_lib/subscribe_handler.h>
+      40             : #include <mrs_lib/publisher_handler.h>
+      41             : #include <mrs_lib/service_client_handler.h>
+      42             : #include <mrs_lib/msg_extractor.h>
+      43             : #include <mrs_lib/geometry/cyclic.h>
+      44             : #include <mrs_lib/geometry/misc.h>
+      45             : #include <mrs_lib/quadratic_throttle_model.h>
+      46             : 
+      47             : //}
+      48             : 
+      49             : /* using //{ */
+      50             : 
+      51             : using vec2_t = mrs_lib::geometry::vec_t<2>;
+      52             : using vec3_t = mrs_lib::geometry::vec_t<3>;
+      53             : 
+      54             : using radians  = mrs_lib::geometry::radians;
+      55             : using sradians = mrs_lib::geometry::sradians;
+      56             : 
+      57             : //}
+      58             : 
+      59             : namespace mrs_uav_managers
+      60             : {
+      61             : 
+      62             : namespace uav_manager
+      63             : {
+      64             : 
+      65             : /* //{ class UavManager */
+      66             : 
+      67             : // state machine
+      68             : typedef enum
+      69             : {
+      70             : 
+      71             :   IDLE_STATE,
+      72             :   FLY_THERE_STATE,
+      73             :   LANDING_STATE,
+      74             : 
+      75             : } LandingStates_t;
+      76             : 
+      77             : const char* state_names[3] = {
+      78             : 
+      79             :     "IDLING", "FLYING HOME", "LANDING"};
+      80             : 
+      81             : class UavManager : public nodelet::Nodelet {
+      82             : 
+      83             : private:
+      84             :   ros::NodeHandle nh_;
+      85             :   bool            is_initialized_ = false;
+      86             :   std::string     _uav_name_;
+      87             : 
+      88             : public:
+      89             :   std::shared_ptr<mrs_lib::Transformer> transformer_;
+      90             : 
+      91             : public:
+      92             :   bool                                       scope_timer_enabled_ = false;
+      93             :   std::shared_ptr<mrs_lib::ScopeTimerLogger> scope_timer_logger_;
+      94             : 
+      95             : public:
+      96             :   virtual void onInit();
+      97             : 
+      98             :   // | ------------------------- HW API ------------------------- |
+      99             : 
+     100             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiCapabilities> sh_hw_api_capabilities_;
+     101             : 
+     102             :   // this timer will check till we already got the hardware api diagnostics
+     103             :   // then it will trigger the initialization of the controllers and finish
+     104             :   // the initialization of the ControlManager
+     105             :   ros::Timer timer_hw_api_capabilities_;
+     106             :   void       timerHwApiCapabilities(const ros::TimerEvent& event);
+     107             : 
+     108             :   void preinitialize(void);
+     109             :   void initialize(void);
+     110             : 
+     111             :   mrs_msgs::HwApiCapabilities hw_api_capabilities_;
+     112             : 
+     113             :   // | ----------------------- subscribers ---------------------- |
+     114             : 
+     115             :   mrs_lib::SubscribeHandler<mrs_msgs::ControllerDiagnostics>        sh_controller_diagnostics_;
+     116             :   mrs_lib::SubscribeHandler<nav_msgs::Odometry>                     sh_odometry_;
+     117             :   mrs_lib::SubscribeHandler<mrs_msgs::EstimationDiagnostics>        sh_estimation_diagnostics_;
+     118             :   mrs_lib::SubscribeHandler<mrs_msgs::ControlManagerDiagnostics>    sh_control_manager_diag_;
+     119             :   mrs_lib::SubscribeHandler<std_msgs::Float64>                      sh_mass_estimate_;
+     120             :   mrs_lib::SubscribeHandler<std_msgs::Float64>                      sh_throttle_;
+     121             :   mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped>               sh_height_;
+     122             :   mrs_lib::SubscribeHandler<mrs_msgs::HwApiStatus>                  sh_hw_api_status_;
+     123             :   mrs_lib::SubscribeHandler<mrs_msgs::GainManagerDiagnostics>       sh_gains_diag_;
+     124             :   mrs_lib::SubscribeHandler<mrs_msgs::ConstraintManagerDiagnostics> sh_constraints_diag_;
+     125             :   mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix>                 sh_hw_api_gnss_;
+     126             :   mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped>               sh_max_height_;
+     127             :   mrs_lib::SubscribeHandler<mrs_msgs::TrackerCommand>               sh_tracker_cmd_;
+     128             : 
+     129             :   void callbackHwApiGNSS(const sensor_msgs::NavSatFix::ConstPtr msg);
+     130             :   void callbackOdometry(const nav_msgs::Odometry::ConstPtr msg);
+     131             : 
+     132             :   // service servers
+     133             :   ros::ServiceServer service_server_takeoff_;
+     134             :   ros::ServiceServer service_server_land_;
+     135             :   ros::ServiceServer service_server_land_home_;
+     136             :   ros::ServiceServer service_server_land_there_;
+     137             :   ros::ServiceServer service_server_midair_activation_;
+     138             : 
+     139             :   // service callbacks
+     140             :   bool callbackTakeoff(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     141             :   bool callbackLand(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     142             :   bool callbackLandHome(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     143             :   bool callbackLandThere(mrs_msgs::ReferenceStampedSrv::Request& req, mrs_msgs::ReferenceStampedSrv::Response& res);
+     144             : 
+     145             :   // service clients
+     146             :   mrs_lib::ServiceClientHandler<mrs_msgs::Vec1>                sch_takeoff_;
+     147             :   mrs_lib::ServiceClientHandler<mrs_msgs::String>              sch_switch_tracker_;
+     148             :   mrs_lib::ServiceClientHandler<mrs_msgs::String>              sch_switch_controller_;
+     149             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger>             sch_land_;
+     150             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger>             sch_eland_;
+     151             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger>             sch_ehover_;
+     152             :   mrs_lib::ServiceClientHandler<std_srvs::SetBool>             sch_control_callbacks_;
+     153             :   mrs_lib::ServiceClientHandler<mrs_msgs::ReferenceStampedSrv> sch_emergency_reference_;
+     154             :   mrs_lib::ServiceClientHandler<std_srvs::SetBool>             sch_arm_;
+     155             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger>             sch_pirouette_;
+     156             :   mrs_lib::ServiceClientHandler<std_srvs::SetBool>             sch_odometry_callbacks_;
+     157             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger>             sch_ungrip_;
+     158             :   mrs_lib::ServiceClientHandler<std_srvs::SetBool>             sch_toggle_control_output_;
+     159             :   mrs_lib::ServiceClientHandler<std_srvs::Trigger>             sch_offboard_;
+     160             : 
+     161             :   // service client wrappers
+     162             :   bool takeoffSrv(void);
+     163             :   bool switchTrackerSrv(const std::string& tracker);
+     164             :   bool switchControllerSrv(const std::string& controller);
+     165             :   bool landSrv(void);
+     166             :   bool elandSrv(void);
+     167             :   bool ehoverSrv(void);
+     168             :   void disarmSrv(void);
+     169             :   bool emergencyReferenceSrv(const mrs_msgs::ReferenceStamped& goal);
+     170             :   void setOdometryCallbacksSrv(const bool& input);
+     171             :   void setControlCallbacksSrv(const bool& input);
+     172             :   void ungripSrv(void);
+     173             :   bool toggleControlOutput(const bool& input);
+     174             :   void pirouetteSrv(void);
+     175             :   bool offboardSrv(const bool in);
+     176             : 
+     177             :   ros::Timer timer_takeoff_;
+     178             :   ros::Timer timer_max_height_;
+     179             :   ros::Timer timer_min_height_;
+     180             :   ros::Timer timer_landing_;
+     181             :   ros::Timer timer_maxthrottle_;
+     182             :   ros::Timer timer_flighttime_;
+     183             :   ros::Timer timer_diagnostics_;
+     184             :   ros::Timer timer_midair_activation_;
+     185             : 
+     186             :   // timer callbacks
+     187             :   void timerLanding(const ros::TimerEvent& event);
+     188             :   void timerTakeoff(const ros::TimerEvent& event);
+     189             :   void timerMaxHeight(const ros::TimerEvent& event);
+     190             :   void timerMinHeight(const ros::TimerEvent& event);
+     191             :   void timerFlightTime(const ros::TimerEvent& event);
+     192             :   void timerMaxthrottle(const ros::TimerEvent& event);
+     193             :   void timerDiagnostics(const ros::TimerEvent& event);
+     194             : 
+     195             :   // publishers
+     196             :   mrs_lib::PublisherHandler<mrs_msgs::UavManagerDiagnostics> ph_diag_;
+     197             : 
+     198             :   // max height checking
+     199             :   bool              _max_height_enabled_ = false;
+     200             :   double            _max_height_checking_rate_;
+     201             :   double            _max_height_offset_;
+     202             :   std::atomic<bool> fixing_max_height_ = false;
+     203             : 
+     204             :   // min height checking
+     205             :   bool              _min_height_enabled_ = false;
+     206             :   double            _min_height_checking_rate_;
+     207             :   double            _min_height_offset_;
+     208             :   double            _min_height_;
+     209             :   std::atomic<bool> fixing_min_height_ = false;
+     210             : 
+     211             :   // mass estimation during landing
+     212             :   double    throttle_mass_estimate_;
+     213             :   bool      throttle_under_threshold_ = false;
+     214             :   ros::Time throttle_mass_estimate_first_time_;
+     215             : 
+     216             :   // velocity during landing
+     217             :   bool      velocity_under_threshold_ = false;
+     218             :   ros::Time velocity_under_threshold_first_time_;
+     219             : 
+     220             :   bool _gain_manager_required_       = false;
+     221             :   bool _constraint_manager_required_ = false;
+     222             : 
+     223             :   std::tuple<bool, std::string> landImpl(void);
+     224             :   std::tuple<bool, std::string> landWithDescendImpl(void);
+     225             :   std::tuple<bool, std::string> midairActivationImpl(void);
+     226             : 
+     227             :   // saved takeoff coordinates and allows to land there again
+     228             :   mrs_msgs::ReferenceStamped land_there_reference_;
+     229             :   std::mutex                 mutex_land_there_reference_;
+     230             : 
+     231             :   // to which height to takeoff
+     232             :   double _takeoff_height_;
+     233             : 
+     234             :   std::atomic<bool> takeoff_successful_ = false;
+     235             : 
+     236             :   // names of important trackers
+     237             :   std::string _null_tracker_name_;
+     238             : 
+     239             :   // takeoff timer
+     240             :   double     _takeoff_timer_rate_;
+     241             :   bool       takingoff_            = false;
+     242             :   int        number_of_takeoffs_   = 0;
+     243             :   double     last_mass_difference_ = 0;
+     244             :   std::mutex mutex_last_mass_difference_;
+     245             :   bool       waiting_for_takeoff_ = false;
+     246             : 
+     247             :   // after takeoff
+     248             :   std::string _after_takeoff_tracker_name_;
+     249             :   std::string _after_takeoff_controller_name_;
+     250             :   std::string _takeoff_tracker_name_;
+     251             :   std::string _takeoff_controller_name_;
+     252             :   bool        _after_takeoff_pirouette_ = false;
+     253             : 
+     254             :   // Landing timer
+     255             :   std::string _landing_tracker_name_;
+     256             :   std::string _landing_controller_name_;
+     257             :   double      _landing_cutoff_mass_factor_;
+     258             :   double      _landing_cutoff_mass_timeout_;
+     259             :   double      _landing_timer_rate_;
+     260             :   double      _landing_descend_height_;
+     261             :   bool        landing_ = false;
+     262             :   double      _uav_mass_;
+     263             :   double      _g_;
+     264             :   double      landing_uav_mass_;
+     265             :   bool        _landing_disarm_ = false;
+     266             :   double      _landing_tracking_tolerance_translation_;
+     267             :   double      _landing_tracking_tolerance_heading_;
+     268             : 
+     269             :   // diagnostics timer
+     270             :   double _diagnostics_timer_rate_;
+     271             : 
+     272             :   mrs_lib::quadratic_throttle_model::MotorParams_t _throttle_model_;
+     273             : 
+     274             :   // landing state machine states
+     275             :   LandingStates_t current_state_landing_  = IDLE_STATE;
+     276             :   LandingStates_t previous_state_landing_ = IDLE_STATE;
+     277             : 
+     278             :   // timer for checking max flight time
+     279             :   double     _flighttime_timer_rate_;
+     280             :   double     _flighttime_max_time_;
+     281             :   bool       _flighttime_timer_enabled_ = false;
+     282             :   double     flighttime_                = 0;
+     283             :   std::mutex mutex_flighttime_;
+     284             : 
+     285             :   // timer for checking maximum throttle
+     286             :   bool      _maxthrottle_timer_enabled_ = false;
+     287             :   double    _maxthrottle_timer_rate_;
+     288             :   double    _maxthrottle_max_throttle_;
+     289             :   double    _maxthrottle_eland_timeout_;
+     290             :   double    _maxthrottle_ungrip_timeout_;
+     291             :   bool      maxthrottle_above_threshold_ = false;
+     292             :   ros::Time maxthrottle_first_time_;
+     293             : 
+     294             :   // profiler
+     295             :   mrs_lib::Profiler profiler_;
+     296             :   bool              _profiler_enabled_ = false;
+     297             : 
+     298             :   // midair activation
+     299             :   void      timerMidairActivation(const ros::TimerEvent& event);
+     300             :   bool      callbackMidairActivation(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res);
+     301             :   ros::Time midair_activation_started_;
+     302             : 
+     303             :   double      _midair_activation_timer_rate_;
+     304             :   std::string _midair_activation_during_controller_;
+     305             :   std::string _midair_activation_during_tracker_;
+     306             :   std::string _midair_activation_after_controller_;
+     307             :   std::string _midair_activation_after_tracker_;
+     308             : 
+     309             :   void changeLandingState(LandingStates_t new_state);
+     310             : };
+     311             : 
+     312             : //}
+     313             : 
+     314             : /* onInit() //{ */
+     315             : 
+     316           7 : void UavManager::onInit() {
+     317           7 :   preinitialize();
+     318           7 : }
+     319             : 
+     320             : //}
+     321             : 
+     322             : /* preinitialize() //{ */
+     323             : 
+     324           7 : void UavManager::preinitialize(void) {
+     325             : 
+     326           7 :   nh_ = nodelet::Nodelet::getMTPrivateNodeHandle();
+     327             : 
+     328           7 :   ros::Time::waitForValid();
+     329             : 
+     330           7 :   mrs_lib::SubscribeHandlerOptions shopts;
+     331           7 :   shopts.nh                 = nh_;
+     332           7 :   shopts.node_name          = "ControlManager";
+     333           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+     334           7 :   shopts.threadsafe         = true;
+     335           7 :   shopts.autostart          = true;
+     336           7 :   shopts.queue_size         = 10;
+     337           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     338             : 
+     339           7 :   sh_hw_api_capabilities_ = mrs_lib::SubscribeHandler<mrs_msgs::HwApiCapabilities>(shopts, "hw_api_capabilities_in");
+     340             : 
+     341           7 :   timer_hw_api_capabilities_ = nh_.createTimer(ros::Rate(1.0), &UavManager::timerHwApiCapabilities, this);
+     342           7 : }
+     343             : 
+     344             : //}
+     345             : 
+     346             : /* initialize() //{ */
+     347             : 
+     348           7 : void UavManager::initialize() {
+     349             : 
+     350           7 :   ROS_INFO("[UavManager]: initializing");
+     351             : 
+     352          14 :   mrs_lib::ParamLoader param_loader(nh_, "UavManager");
+     353             : 
+     354          14 :   std::string custom_config_path;
+     355          14 :   std::string platform_config_path;
+     356          14 :   std::string world_config_path;
+     357             : 
+     358           7 :   param_loader.loadParam("custom_config", custom_config_path);
+     359           7 :   param_loader.loadParam("platform_config", platform_config_path);
+     360           7 :   param_loader.loadParam("world_config", world_config_path);
+     361             : 
+     362           7 :   if (custom_config_path != "") {
+     363           7 :     param_loader.addYamlFile(custom_config_path);
+     364             :   }
+     365             : 
+     366           7 :   if (platform_config_path != "") {
+     367           7 :     param_loader.addYamlFile(platform_config_path);
+     368             :   }
+     369             : 
+     370           7 :   if (world_config_path != "") {
+     371           7 :     param_loader.addYamlFile(world_config_path);
+     372             :   }
+     373             : 
+     374           7 :   param_loader.addYamlFileFromParam("private_config");
+     375           7 :   param_loader.addYamlFileFromParam("public_config");
+     376             : 
+     377          14 :   const std::string yaml_prefix = "mrs_uav_managers/uav_manager/";
+     378             : 
+     379             :   // params passed from the launch file are not prefixed
+     380           7 :   param_loader.loadParam("uav_name", _uav_name_);
+     381           7 :   param_loader.loadParam("enable_profiler", _profiler_enabled_);
+     382           7 :   param_loader.loadParam("uav_mass", _uav_mass_);
+     383           7 :   param_loader.loadParam("g", _g_);
+     384             : 
+     385             :   // motor params are also not prefixed, since they are common to more nodes
+     386           7 :   param_loader.loadParam("motor_params/n_motors", _throttle_model_.n_motors);
+     387           7 :   param_loader.loadParam("motor_params/a", _throttle_model_.A);
+     388           7 :   param_loader.loadParam("motor_params/b", _throttle_model_.B);
+     389             : 
+     390           7 :   param_loader.loadParam(yaml_prefix + "null_tracker", _null_tracker_name_);
+     391             : 
+     392           7 :   param_loader.loadParam(yaml_prefix + "takeoff/rate", _takeoff_timer_rate_);
+     393           7 :   param_loader.loadParam(yaml_prefix + "takeoff/after_takeoff/tracker", _after_takeoff_tracker_name_);
+     394           7 :   param_loader.loadParam(yaml_prefix + "takeoff/after_takeoff/controller", _after_takeoff_controller_name_);
+     395           7 :   param_loader.loadParam(yaml_prefix + "takeoff/after_takeoff/pirouette", _after_takeoff_pirouette_);
+     396           7 :   param_loader.loadParam(yaml_prefix + "takeoff/during_takeoff/controller", _takeoff_controller_name_);
+     397           7 :   param_loader.loadParam(yaml_prefix + "takeoff/during_takeoff/tracker", _takeoff_tracker_name_);
+     398           7 :   param_loader.loadParam(yaml_prefix + "takeoff/takeoff_height", _takeoff_height_);
+     399             : 
+     400           7 :   param_loader.loadParam(yaml_prefix + "landing/rate", _landing_timer_rate_);
+     401           7 :   param_loader.loadParam(yaml_prefix + "landing/landing_tracker", _landing_tracker_name_);
+     402           7 :   param_loader.loadParam(yaml_prefix + "landing/landing_controller", _landing_controller_name_);
+     403           7 :   param_loader.loadParam(yaml_prefix + "landing/landing_cutoff_mass_factor", _landing_cutoff_mass_factor_);
+     404           7 :   param_loader.loadParam(yaml_prefix + "landing/landing_cutoff_timeout", _landing_cutoff_mass_timeout_);
+     405           7 :   param_loader.loadParam(yaml_prefix + "landing/disarm", _landing_disarm_);
+     406           7 :   param_loader.loadParam(yaml_prefix + "landing/descend_height", _landing_descend_height_);
+     407           7 :   param_loader.loadParam(yaml_prefix + "landing/tracking_tolerance/translation", _landing_tracking_tolerance_translation_);
+     408           7 :   param_loader.loadParam(yaml_prefix + "landing/tracking_tolerance/heading", _landing_tracking_tolerance_heading_);
+     409             : 
+     410           7 :   param_loader.loadParam(yaml_prefix + "midair_activation/rate", _midair_activation_timer_rate_);
+     411           7 :   param_loader.loadParam(yaml_prefix + "midair_activation/during_activation/controller", _midair_activation_during_controller_);
+     412           7 :   param_loader.loadParam(yaml_prefix + "midair_activation/during_activation/tracker", _midair_activation_during_tracker_);
+     413           7 :   param_loader.loadParam(yaml_prefix + "midair_activation/after_activation/controller", _midair_activation_after_controller_);
+     414           7 :   param_loader.loadParam(yaml_prefix + "midair_activation/after_activation/tracker", _midair_activation_after_tracker_);
+     415             : 
+     416           7 :   param_loader.loadParam(yaml_prefix + "max_height_checking/enabled", _max_height_enabled_);
+     417           7 :   param_loader.loadParam(yaml_prefix + "max_height_checking/rate", _max_height_checking_rate_);
+     418           7 :   param_loader.loadParam(yaml_prefix + "max_height_checking/safety_height_offset", _max_height_offset_);
+     419             : 
+     420           7 :   param_loader.loadParam(yaml_prefix + "min_height_checking/enabled", _min_height_enabled_);
+     421           7 :   param_loader.loadParam(yaml_prefix + "min_height_checking/rate", _min_height_checking_rate_);
+     422           7 :   param_loader.loadParam(yaml_prefix + "min_height_checking/safety_height_offset", _min_height_offset_);
+     423           7 :   param_loader.loadParam(yaml_prefix + "min_height_checking/min_height", _min_height_);
+     424             : 
+     425           7 :   param_loader.loadParam(yaml_prefix + "require_gain_manager", _gain_manager_required_);
+     426           7 :   param_loader.loadParam(yaml_prefix + "require_constraint_manager", _constraint_manager_required_);
+     427             : 
+     428           7 :   param_loader.loadParam(yaml_prefix + "flight_timer/enabled", _flighttime_timer_enabled_);
+     429           7 :   param_loader.loadParam(yaml_prefix + "flight_timer/rate", _flighttime_timer_rate_);
+     430           7 :   param_loader.loadParam(yaml_prefix + "flight_timer/max_time", _flighttime_max_time_);
+     431             : 
+     432           7 :   param_loader.loadParam(yaml_prefix + "max_throttle/enabled", _maxthrottle_timer_enabled_);
+     433           7 :   param_loader.loadParam(yaml_prefix + "max_throttle/rate", _maxthrottle_timer_rate_);
+     434           7 :   param_loader.loadParam(yaml_prefix + "max_throttle/max_throttle", _maxthrottle_max_throttle_);
+     435           7 :   param_loader.loadParam(yaml_prefix + "max_throttle/eland_timeout", _maxthrottle_eland_timeout_);
+     436           7 :   param_loader.loadParam(yaml_prefix + "max_throttle/ungrip_timeout", _maxthrottle_ungrip_timeout_);
+     437             : 
+     438           7 :   param_loader.loadParam(yaml_prefix + "diagnostics/rate", _diagnostics_timer_rate_);
+     439             : 
+     440             :   // | ------------------- scope timer logger ------------------- |
+     441             : 
+     442           7 :   param_loader.loadParam(yaml_prefix + "scope_timer/enabled", scope_timer_enabled_);
+     443          21 :   const std::string scope_timer_log_filename = param_loader.loadParam2("scope_timer/log_filename", std::string(""));
+     444           7 :   scope_timer_logger_                        = std::make_shared<mrs_lib::ScopeTimerLogger>(scope_timer_log_filename, scope_timer_enabled_);
+     445             : 
+     446           7 :   if (!param_loader.loadedSuccessfully()) {
+     447           0 :     ROS_ERROR("[UavManager]: Could not load all parameters!");
+     448           0 :     ros::shutdown();
+     449             :   }
+     450             : 
+     451             :   // | --------------------- tf transformer --------------------- |
+     452             : 
+     453           7 :   transformer_ = std::make_shared<mrs_lib::Transformer>(nh_, "ControlManager");
+     454           7 :   transformer_->setDefaultPrefix(_uav_name_);
+     455           7 :   transformer_->retryLookupNewest(true);
+     456             : 
+     457             :   // | ----------------------- subscribers ---------------------- |
+     458             : 
+     459          14 :   mrs_lib::SubscribeHandlerOptions shopts;
+     460           7 :   shopts.nh                 = nh_;
+     461           7 :   shopts.node_name          = "UavManager";
+     462           7 :   shopts.no_message_timeout = mrs_lib::no_timeout;
+     463           7 :   shopts.threadsafe         = true;
+     464           7 :   shopts.autostart          = true;
+     465           7 :   shopts.queue_size         = 10;
+     466           7 :   shopts.transport_hints    = ros::TransportHints().tcpNoDelay();
+     467             : 
+     468           7 :   sh_controller_diagnostics_ = mrs_lib::SubscribeHandler<mrs_msgs::ControllerDiagnostics>(shopts, "controller_diagnostics_in");
+     469           7 :   sh_odometry_               = mrs_lib::SubscribeHandler<nav_msgs::Odometry>(shopts, "odometry_in", &UavManager::callbackOdometry, this);
+     470           7 :   sh_estimation_diagnostics_ = mrs_lib::SubscribeHandler<mrs_msgs::EstimationDiagnostics>(shopts, "odometry_diagnostics_in");
+     471           7 :   sh_control_manager_diag_   = mrs_lib::SubscribeHandler<mrs_msgs::ControlManagerDiagnostics>(shopts, "control_manager_diagnostics_in");
+     472           7 :   sh_mass_estimate_          = mrs_lib::SubscribeHandler<std_msgs::Float64>(shopts, "mass_estimate_in");
+     473           7 :   sh_throttle_               = mrs_lib::SubscribeHandler<std_msgs::Float64>(shopts, "throttle_in");
+     474           7 :   sh_height_                 = mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped>(shopts, "height_in");
+     475           7 :   sh_hw_api_status_          = mrs_lib::SubscribeHandler<mrs_msgs::HwApiStatus>(shopts, "hw_api_status_in");
+     476           7 :   sh_gains_diag_             = mrs_lib::SubscribeHandler<mrs_msgs::GainManagerDiagnostics>(shopts, "gain_manager_diagnostics_in");
+     477           7 :   sh_constraints_diag_       = mrs_lib::SubscribeHandler<mrs_msgs::ConstraintManagerDiagnostics>(shopts, "constraint_manager_diagnostics_in");
+     478           7 :   sh_hw_api_gnss_            = mrs_lib::SubscribeHandler<sensor_msgs::NavSatFix>(shopts, "hw_api_gnss_in", &UavManager::callbackHwApiGNSS, this);
+     479           7 :   sh_max_height_             = mrs_lib::SubscribeHandler<mrs_msgs::Float64Stamped>(shopts, "max_height_in");
+     480           7 :   sh_tracker_cmd_            = mrs_lib::SubscribeHandler<mrs_msgs::TrackerCommand>(shopts, "tracker_cmd_in");
+     481             : 
+     482             :   // | ----------------------- publishers ----------------------- |
+     483             : 
+     484           7 :   ph_diag_ = mrs_lib::PublisherHandler<mrs_msgs::UavManagerDiagnostics>(nh_, "diagnostics_out", 1);
+     485             : 
+     486             :   // | --------------------- service servers -------------------- |
+     487             : 
+     488           7 :   service_server_takeoff_           = nh_.advertiseService("takeoff_in", &UavManager::callbackTakeoff, this);
+     489           7 :   service_server_land_              = nh_.advertiseService("land_in", &UavManager::callbackLand, this);
+     490           7 :   service_server_land_home_         = nh_.advertiseService("land_home_in", &UavManager::callbackLandHome, this);
+     491           7 :   service_server_land_there_        = nh_.advertiseService("land_there_in", &UavManager::callbackLandThere, this);
+     492           7 :   service_server_midair_activation_ = nh_.advertiseService("midair_activation_in", &UavManager::callbackMidairActivation, this);
+     493             : 
+     494             :   // | --------------------- service clients -------------------- |
+     495             : 
+     496           7 :   sch_takeoff_               = mrs_lib::ServiceClientHandler<mrs_msgs::Vec1>(nh_, "takeoff_out");
+     497           7 :   sch_land_                  = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "land_out");
+     498           7 :   sch_eland_                 = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "eland_out");
+     499           7 :   sch_ehover_                = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "ehover_out");
+     500           7 :   sch_switch_tracker_        = mrs_lib::ServiceClientHandler<mrs_msgs::String>(nh_, "switch_tracker_out");
+     501           7 :   sch_switch_controller_     = mrs_lib::ServiceClientHandler<mrs_msgs::String>(nh_, "switch_controller_out");
+     502           7 :   sch_emergency_reference_   = mrs_lib::ServiceClientHandler<mrs_msgs::ReferenceStampedSrv>(nh_, "emergency_reference_out");
+     503           7 :   sch_control_callbacks_     = mrs_lib::ServiceClientHandler<std_srvs::SetBool>(nh_, "enable_callbacks_out");
+     504           7 :   sch_arm_                   = mrs_lib::ServiceClientHandler<std_srvs::SetBool>(nh_, "arm_out");
+     505           7 :   sch_pirouette_             = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "pirouette_out");
+     506           7 :   sch_odometry_callbacks_    = mrs_lib::ServiceClientHandler<std_srvs::SetBool>(nh_, "set_odometry_callbacks_out");
+     507           7 :   sch_ungrip_                = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "ungrip_out");
+     508           7 :   sch_toggle_control_output_ = mrs_lib::ServiceClientHandler<std_srvs::SetBool>(nh_, "toggle_control_output_out");
+     509           7 :   sch_offboard_              = mrs_lib::ServiceClientHandler<std_srvs::Trigger>(nh_, "offboard_out");
+     510             : 
+     511             :   // | ---------------------- state machine --------------------- |
+     512             : 
+     513           7 :   current_state_landing_ = IDLE_STATE;
+     514             : 
+     515             :   // | ------------------------ profiler ------------------------ |
+     516             : 
+     517           7 :   profiler_ = mrs_lib::Profiler(nh_, "UavManager", _profiler_enabled_);
+     518             : 
+     519             :   // | ------------------------- timers ------------------------- |
+     520             : 
+     521           7 :   timer_landing_           = nh_.createTimer(ros::Rate(_landing_timer_rate_), &UavManager::timerLanding, this, false, false);
+     522           7 :   timer_takeoff_           = nh_.createTimer(ros::Rate(_takeoff_timer_rate_), &UavManager::timerTakeoff, this, false, false);
+     523           7 :   timer_flighttime_        = nh_.createTimer(ros::Rate(_flighttime_timer_rate_), &UavManager::timerFlightTime, this, false, false);
+     524           7 :   timer_diagnostics_       = nh_.createTimer(ros::Rate(_diagnostics_timer_rate_), &UavManager::timerDiagnostics, this);
+     525           7 :   timer_midair_activation_ = nh_.createTimer(ros::Rate(_midair_activation_timer_rate_), &UavManager::timerMidairActivation, this, false, false);
+     526          14 :   timer_max_height_        = nh_.createTimer(ros::Rate(_max_height_checking_rate_), &UavManager::timerMaxHeight, this, false,
+     527          14 :                                       _max_height_enabled_ && hw_api_capabilities_.produces_distance_sensor);
+     528          14 :   timer_min_height_        = nh_.createTimer(ros::Rate(_min_height_checking_rate_), &UavManager::timerMinHeight, this, false,
+     529          14 :                                       _min_height_enabled_ && hw_api_capabilities_.produces_distance_sensor);
+     530             : 
+     531           7 :   bool should_check_throttle = hw_api_capabilities_.accepts_actuator_cmd || hw_api_capabilities_.accepts_control_group_cmd ||
+     532          14 :                                hw_api_capabilities_.accepts_attitude_rate_cmd || hw_api_capabilities_.accepts_attitude_cmd;
+     533             : 
+     534             :   timer_maxthrottle_ =
+     535           7 :       nh_.createTimer(ros::Rate(_maxthrottle_timer_rate_), &UavManager::timerMaxthrottle, this, false, _maxthrottle_timer_enabled_ && should_check_throttle);
+     536             : 
+     537             :   // | ----------------------- finish init ---------------------- |
+     538             : 
+     539           7 :   is_initialized_ = true;
+     540             : 
+     541           7 :   ROS_INFO("[UavManager]: initialized");
+     542             : 
+     543           7 :   ROS_DEBUG("[UavManager]: debug output is enabled");
+     544           7 : }
+     545             : 
+     546             : //}
+     547             : 
+     548             : //}
+     549             : 
+     550             : // | ---------------------- state machine --------------------- |
+     551             : 
+     552             : /* //{ changeLandingState() */
+     553             : 
+     554           2 : void UavManager::changeLandingState(LandingStates_t new_state) {
+     555             : 
+     556           2 :   previous_state_landing_ = current_state_landing_;
+     557           2 :   current_state_landing_  = new_state;
+     558             : 
+     559           2 :   switch (current_state_landing_) {
+     560             : 
+     561           1 :     case LANDING_STATE: {
+     562             : 
+     563           1 :       if (sh_mass_estimate_.hasMsg() && (ros::Time::now() - sh_mass_estimate_.lastMsgTime()).toSec() < 1.0) {
+     564             : 
+     565             :         // copy member variables
+     566           1 :         auto mass_esimtate = sh_mass_estimate_.getMsg();
+     567             : 
+     568           1 :         landing_uav_mass_ = mass_esimtate->data;
+     569             :       }
+     570             : 
+     571           1 :       break;
+     572             :     };
+     573             : 
+     574           1 :     default: {
+     575           1 :       break;
+     576             :     }
+     577             :   }
+     578             : 
+     579             :   // just for ROS_INFO
+     580           2 :   ROS_INFO("[UavManager]: Switching landing state %s -> %s", state_names[previous_state_landing_], state_names[current_state_landing_]);
+     581           2 : }
+     582             : 
+     583             : //}
+     584             : 
+     585             : // --------------------------------------------------------------
+     586             : // |                           timers                           |
+     587             : // --------------------------------------------------------------
+     588             : 
+     589             : /* timerHwApiCapabilities() //{ */
+     590             : 
+     591           7 : void UavManager::timerHwApiCapabilities(const ros::TimerEvent& event) {
+     592             : 
+     593          14 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerHwApiCapabilities", 1.0, 1.0, event);
+     594          14 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("ControlManager::timerHwApiCapabilities", scope_timer_logger_, scope_timer_enabled_);
+     595             : 
+     596           7 :   if (!sh_hw_api_capabilities_.hasMsg()) {
+     597           0 :     ROS_INFO_THROTTLE(1.0, "[ControlManager]: waiting for HW API capabilities");
+     598           0 :     return;
+     599             :   }
+     600             : 
+     601           7 :   hw_api_capabilities_ = *sh_hw_api_capabilities_.getMsg();
+     602             : 
+     603           7 :   ROS_INFO("[ControlManager]: got HW API capabilities, initializing");
+     604             : 
+     605           7 :   initialize();
+     606             : 
+     607           7 :   timer_hw_api_capabilities_.stop();
+     608             : }
+     609             : 
+     610             : //}
+     611             : 
+     612             : /* //{ timerLanding() */
+     613             : 
+     614          83 : void UavManager::timerLanding(const ros::TimerEvent& event) {
+     615             : 
+     616          83 :   if (!is_initialized_)
+     617           0 :     return;
+     618             : 
+     619         166 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerLanding", _landing_timer_rate_, 0.1, event);
+     620         166 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::timerLanding", scope_timer_logger_, scope_timer_enabled_);
+     621             : 
+     622          83 :   auto land_there_reference = mrs_lib::get_mutexed(mutex_land_there_reference_, land_there_reference_);
+     623             : 
+     624             :   // copy member variables
+     625          83 :   auto control_manager_diagnostics = sh_control_manager_diag_.getMsg();
+     626          83 :   auto odometry                    = sh_odometry_.getMsg();
+     627          83 :   auto tracker_cmd                 = sh_tracker_cmd_.getMsg();
+     628             : 
+     629          83 :   std::optional<double> desired_throttle;
+     630             : 
+     631          83 :   if (sh_throttle_.hasMsg() && (ros::Time::now() - sh_throttle_.lastMsgTime()).toSec() < 1.0) {
+     632          83 :     desired_throttle = sh_throttle_.getMsg()->data;
+     633             :   }
+     634             : 
+     635          83 :   auto res = transformer_->transformSingle(land_there_reference, odometry->header.frame_id);
+     636             : 
+     637          83 :   mrs_msgs::ReferenceStamped land_there_current_frame;
+     638             : 
+     639          83 :   if (res) {
+     640          83 :     land_there_current_frame = res.value();
+     641             :   } else {
+     642             : 
+     643           0 :     ROS_ERROR("[UavManager]: could not transform the reference into the current frame! land by yourself pls.");
+     644           0 :     return;
+     645             :   }
+     646             : 
+     647          83 :   if (current_state_landing_ == IDLE_STATE) {
+     648             : 
+     649           0 :     return;
+     650             : 
+     651          83 :   } else if (current_state_landing_ == FLY_THERE_STATE) {
+     652             : 
+     653           0 :     auto [pos_x, pos_y, pos_z] = mrs_lib::getPosition(*tracker_cmd);
+     654           0 :     auto [ref_x, ref_y, ref_z] = mrs_lib::getPosition(land_there_current_frame);
+     655             : 
+     656           0 :     double pos_heading = tracker_cmd->heading;
+     657             : 
+     658           0 :     double ref_heading = 0;
+     659             :     try {
+     660           0 :       ref_heading = mrs_lib::getHeading(land_there_current_frame);
+     661             :     }
+     662           0 :     catch (mrs_lib::AttitudeConverter::GetHeadingException& e) {
+     663           0 :       ROS_ERROR_THROTTLE(1.0, "[UavManager]: exception caught: '%s'", e.what());
+     664           0 :       return;
+     665             :     }
+     666             : 
+     667           0 :     if (mrs_lib::geometry::dist(vec3_t(pos_x, pos_y, pos_z), vec3_t(ref_x, ref_y, ref_z)) < _landing_tracking_tolerance_translation_ &&
+     668           0 :         fabs(radians::diff(pos_heading, ref_heading)) < _landing_tracking_tolerance_heading_) {
+     669             : 
+     670           0 :       auto [success, message] = landWithDescendImpl();
+     671             : 
+     672           0 :       if (!success) {
+     673             : 
+     674           0 :         ROS_ERROR_THROTTLE(1.0, "[UavManager]: call for landing failed: '%s'", message.c_str());
+     675             :       }
+     676             : 
+     677           0 :     } else if (!control_manager_diagnostics->tracker_status.have_goal && control_manager_diagnostics->flying_normally) {
+     678             : 
+     679           0 :       ROS_WARN_THROTTLE(1.0, "[UavManager]: the tracker does not have a goal while flying home, setting the reference again");
+     680             : 
+     681           0 :       mrs_msgs::ReferenceStamped reference_out;
+     682             : 
+     683             :       {
+     684           0 :         std::scoped_lock lock(mutex_land_there_reference_);
+     685             : 
+     686             :         // get the current altitude in land_there_reference_.header.frame_id;
+     687           0 :         geometry_msgs::PoseStamped current_pose;
+     688           0 :         current_pose.header.stamp     = ros::Time::now();
+     689           0 :         current_pose.header.frame_id  = _uav_name_ + "/fcu";
+     690           0 :         current_pose.pose.position.x  = 0;
+     691           0 :         current_pose.pose.position.y  = 0;
+     692           0 :         current_pose.pose.position.z  = 0;
+     693           0 :         current_pose.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+     694             : 
+     695           0 :         auto response = transformer_->transformSingle(current_pose, land_there_reference_.header.frame_id);
+     696             : 
+     697           0 :         if (response) {
+     698             : 
+     699           0 :           land_there_reference_.reference.position.z = response.value().pose.position.z;
+     700           0 :           ROS_DEBUG("[UavManager]: current altitude is %.2f m", land_there_reference_.reference.position.z);
+     701             : 
+     702             :         } else {
+     703             : 
+     704           0 :           std::stringstream ss;
+     705           0 :           ss << "could not transform current height to " << land_there_reference_.header.frame_id;
+     706           0 :           ROS_ERROR_STREAM("[UavManager]: " << ss.str());
+     707             :         }
+     708             : 
+     709           0 :         reference_out.header.frame_id = land_there_reference_.header.frame_id;
+     710           0 :         reference_out.header.stamp    = ros::Time::now();
+     711           0 :         reference_out.reference       = land_there_reference_.reference;
+     712             :       }
+     713             : 
+     714           0 :       emergencyReferenceSrv(reference_out);
+     715             :     }
+     716             : 
+     717          83 :   } else if (current_state_landing_ == LANDING_STATE) {
+     718             : 
+     719             :     // we should not attempt to finish the landing if some other tracked was activated
+     720          83 :     if (_landing_tracker_name_ == sh_control_manager_diag_.getMsg()->active_tracker) {
+     721             : 
+     722          83 :       if (desired_throttle) {
+     723             : 
+     724             :         // recalculate the mass based on the throttle
+     725          83 :         throttle_mass_estimate_ = mrs_lib::quadratic_throttle_model::throttleToForce(_throttle_model_, desired_throttle.value()) / _g_;
+     726          83 :         ROS_INFO_THROTTLE(1.0, "[UavManager]: landing: initial mass: %.2f throttle_mass_estimate: %.2f", landing_uav_mass_, throttle_mass_estimate_);
+     727             : 
+     728             :         // condition for automatic motor turn off
+     729          83 :         if (((throttle_mass_estimate_ < _landing_cutoff_mass_factor_ * landing_uav_mass_) || desired_throttle < 0.01)) {
+     730             : 
+     731          22 :           if (!throttle_under_threshold_) {
+     732             : 
+     733           1 :             throttle_mass_estimate_first_time_ = ros::Time::now();
+     734           1 :             throttle_under_threshold_          = true;
+     735             :           }
+     736             : 
+     737          22 :           ROS_INFO_THROTTLE(0.5, "[UavManager]: throttle is under cutoff factor for %.2f s", (ros::Time::now() - throttle_mass_estimate_first_time_).toSec());
+     738             : 
+     739             :         } else {
+     740             : 
+     741          61 :           throttle_under_threshold_ = false;
+     742             :         }
+     743             : 
+     744          83 :         if (throttle_under_threshold_ && ((ros::Time::now() - throttle_mass_estimate_first_time_).toSec() > _landing_cutoff_mass_timeout_)) {
+     745             : 
+     746           1 :           switchTrackerSrv(_null_tracker_name_);
+     747             : 
+     748           1 :           setControlCallbacksSrv(true);
+     749             : 
+     750           1 :           if (_landing_disarm_) {
+     751             : 
+     752           1 :             ROS_INFO("[UavManager]: disarming after landing");
+     753             : 
+     754           1 :             disarmSrv();
+     755             :           }
+     756             : 
+     757           1 :           changeLandingState(IDLE_STATE);
+     758             : 
+     759           1 :           ROS_INFO("[UavManager]: landing finished");
+     760             : 
+     761           1 :           timer_landing_.stop();
+     762             :         }
+     763             : 
+     764             :       } else {
+     765             : 
+     766           0 :         auto odometry = sh_odometry_.getMsg();
+     767             : 
+     768           0 :         double z_vel = odometry->twist.twist.linear.z;
+     769             : 
+     770           0 :         ROS_INFO_THROTTLE(1.0, "[UavManager]: landing: z-velocity: %.2f", z_vel);
+     771             : 
+     772             :         // condition for automatic motor turn off
+     773           0 :         if (z_vel > -0.1) {
+     774             : 
+     775           0 :           if (!velocity_under_threshold_) {
+     776             : 
+     777           0 :             velocity_under_threshold_first_time_ = ros::Time::now();
+     778           0 :             velocity_under_threshold_            = true;
+     779             :           }
+     780             : 
+     781           0 :           ROS_INFO_THROTTLE(0.5, "[UavManager]: velocity over threshold for %.2f s", (ros::Time::now() - velocity_under_threshold_first_time_).toSec());
+     782             : 
+     783             :         } else {
+     784             : 
+     785           0 :           velocity_under_threshold_ = false;
+     786             :         }
+     787             : 
+     788           0 :         if (velocity_under_threshold_ && ((ros::Time::now() - velocity_under_threshold_first_time_).toSec() > 3.0)) {
+     789             : 
+     790           0 :           switchTrackerSrv(_null_tracker_name_);
+     791             : 
+     792           0 :           setControlCallbacksSrv(true);
+     793             : 
+     794           0 :           if (_landing_disarm_) {
+     795             : 
+     796           0 :             ROS_INFO("[UavManager]: disarming after landing");
+     797             : 
+     798           0 :             disarmSrv();
+     799             :           }
+     800             : 
+     801           0 :           changeLandingState(IDLE_STATE);
+     802             : 
+     803           0 :           ROS_INFO("[UavManager]: landing finished");
+     804             : 
+     805           0 :           timer_landing_.stop();
+     806             :         }
+     807             :       }
+     808             : 
+     809             :     } else {
+     810             : 
+     811           0 :       ROS_WARN_THROTTLE(1.0, "[UavManager]: incorrect tracker detected during landing!");
+     812             :     }
+     813             :   }
+     814             : }
+     815             : 
+     816             : //}
+     817             : 
+     818             : /* //{ timerTakeoff() */
+     819             : 
+     820          48 : void UavManager::timerTakeoff(const ros::TimerEvent& event) {
+     821             : 
+     822          48 :   if (!is_initialized_)
+     823           0 :     return;
+     824             : 
+     825          96 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerTakeoff", _takeoff_timer_rate_, 0.1, event);
+     826          96 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::timerTakeoff", scope_timer_logger_, scope_timer_enabled_);
+     827             : 
+     828          48 :   auto control_manager_diagnostics = sh_control_manager_diag_.getMsg();
+     829             : 
+     830          48 :   if (waiting_for_takeoff_) {
+     831             : 
+     832           1 :     if (control_manager_diagnostics->active_tracker == _takeoff_tracker_name_ && control_manager_diagnostics->tracker_status.have_goal) {
+     833             : 
+     834           1 :       waiting_for_takeoff_ = false;
+     835             :     } else {
+     836             : 
+     837           0 :       ROS_WARN_THROTTLE(1.0, "[UavManager]: waiting for takeoff confirmation from the ControlManager");
+     838           0 :       return;
+     839             :     }
+     840             :   }
+     841             : 
+     842          48 :   if (takingoff_) {
+     843             : 
+     844          48 :     if (control_manager_diagnostics->active_tracker != _takeoff_tracker_name_ || !control_manager_diagnostics->tracker_status.have_goal) {
+     845             : 
+     846           1 :       ROS_INFO("[UavManager]: take off finished, switching to %s", _after_takeoff_tracker_name_.c_str());
+     847             : 
+     848           1 :       switchTrackerSrv(_after_takeoff_tracker_name_);
+     849             : 
+     850           1 :       switchControllerSrv(_after_takeoff_controller_name_);
+     851             : 
+     852           1 :       setOdometryCallbacksSrv(true);
+     853             : 
+     854           1 :       if (_after_takeoff_pirouette_) {
+     855             : 
+     856           0 :         pirouetteSrv();
+     857             :       }
+     858             : 
+     859           1 :       timer_takeoff_.stop();
+     860             :     }
+     861             :   }
+     862             : }
+     863             : 
+     864             : //}
+     865             : 
+     866             : /* //{ timerMaxHeight() */
+     867             : 
+     868        1117 : void UavManager::timerMaxHeight(const ros::TimerEvent& event) {
+     869             : 
+     870        1117 :   if (!is_initialized_)
+     871         959 :     return;
+     872             : 
+     873        2234 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerMaxHeight", _max_height_checking_rate_, 0.1, event);
+     874        2234 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::timerMaxHeight", scope_timer_logger_, scope_timer_enabled_);
+     875             : 
+     876        1117 :   if (!sh_max_height_.hasMsg() || !sh_height_.hasMsg() || !sh_odometry_.hasMsg()) {
+     877         639 :     ROS_WARN_THROTTLE(10.0, "[UavManager]: maxHeightTimer() not spinning, missing data");
+     878         639 :     return;
+     879             :   }
+     880             : 
+     881         478 :   auto control_manager_diag = sh_control_manager_diag_.getMsg();
+     882             : 
+     883         478 :   if (!control_manager_diag->flying_normally) {
+     884         320 :     return;
+     885             :   }
+     886             : 
+     887         158 :   auto   odometry = sh_odometry_.getMsg();
+     888         158 :   double height   = sh_height_.getMsg()->value;
+     889             : 
+     890             :   // transform max z to the height frame
+     891         158 :   geometry_msgs::PointStamped point;
+     892         158 :   point.header  = sh_max_height_.getMsg()->header;
+     893         158 :   point.point.z = sh_max_height_.getMsg()->value;
+     894             : 
+     895         158 :   auto res = transformer_->transformSingle(point, sh_height_.getMsg()->header.frame_id);
+     896             : 
+     897             :   double max_z_in_height;
+     898             : 
+     899         158 :   if (res) {
+     900         158 :     max_z_in_height = res->point.z;
+     901             :   } else {
+     902           0 :     ROS_WARN_THROTTLE(1.0, "[UavManager]: timerMaxHeight() not working, cannot transform max z to the height frame");
+     903           0 :     return;
+     904             :   }
+     905             : 
+     906         158 :   auto [odometry_x, odometry_y, odometry_z] = mrs_lib::getPosition(odometry);
+     907             : 
+     908         158 :   double odometry_heading = 0;
+     909             :   try {
+     910         158 :     odometry_heading = mrs_lib::getHeading(odometry);
+     911             :   }
+     912           0 :   catch (mrs_lib::AttitudeConverter::GetHeadingException& e) {
+     913           0 :     ROS_ERROR_THROTTLE(1.0, "[UavManager]: exception caught: '%s'", e.what());
+     914           0 :     return;
+     915             :   }
+     916             : 
+     917         158 :   if (height > max_z_in_height) {
+     918             : 
+     919           0 :     ROS_WARN_THROTTLE(1.0, "[UavManager]: max height exceeded: %.2f >  %.2f, triggering safety goto", height, max_z_in_height);
+     920             : 
+     921           0 :     mrs_msgs::ReferenceStamped reference_out;
+     922           0 :     reference_out.header.frame_id = odometry->header.frame_id;
+     923           0 :     reference_out.header.stamp    = ros::Time::now();
+     924             : 
+     925           0 :     reference_out.reference.position.x = odometry_x;
+     926           0 :     reference_out.reference.position.y = odometry_y;
+     927           0 :     reference_out.reference.position.z = odometry_z + ((max_z_in_height - _max_height_offset_) - height);
+     928             : 
+     929           0 :     reference_out.reference.heading = odometry_heading;
+     930             : 
+     931           0 :     setControlCallbacksSrv(false);
+     932             : 
+     933           0 :     bool success = emergencyReferenceSrv(reference_out);
+     934             : 
+     935           0 :     if (success) {
+     936             : 
+     937           0 :       ROS_INFO("[UavManager]: descending");
+     938             : 
+     939           0 :       fixing_max_height_ = true;
+     940             : 
+     941             :     } else {
+     942             : 
+     943           0 :       ROS_ERROR_THROTTLE(1.0, "[UavManager]: could not descend");
+     944             : 
+     945           0 :       setControlCallbacksSrv(true);
+     946             :     }
+     947             :   }
+     948             : 
+     949         158 :   if (fixing_max_height_ && height < max_z_in_height) {
+     950             : 
+     951           0 :     setControlCallbacksSrv(true);
+     952             : 
+     953           0 :     ROS_WARN_THROTTLE(1.0, "[UavManager]: safe height reached");
+     954             : 
+     955           0 :     fixing_max_height_ = false;
+     956             :   }
+     957             : }
+     958             : 
+     959             : //}
+     960             : 
+     961             : /* //{ timerMinHeight() */
+     962             : 
+     963        1117 : void UavManager::timerMinHeight(const ros::TimerEvent& event) {
+     964             : 
+     965        1117 :   if (!is_initialized_)
+     966         959 :     return;
+     967             : 
+     968        1117 :   ROS_INFO_ONCE("[UavManager]: min height timer spinning");
+     969             : 
+     970        2234 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerMinHeight", _min_height_checking_rate_, 0.1, event);
+     971        2234 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::timerMinHeight", scope_timer_logger_, scope_timer_enabled_);
+     972             : 
+     973        1117 :   if (!sh_odometry_.hasMsg() || !sh_height_.hasMsg() || !sh_control_manager_diag_.hasMsg()) {
+     974         638 :     ROS_WARN_THROTTLE(10.0, "[UavManager]: minHeightTimer() not spinning, missing data");
+     975         638 :     return;
+     976             :   }
+     977             : 
+     978         479 :   auto control_manager_diag = sh_control_manager_diag_.getMsg();
+     979             : 
+     980         479 :   if (!control_manager_diag->flying_normally) {
+     981         321 :     return;
+     982             :   }
+     983             : 
+     984         158 :   auto   odometry = sh_odometry_.getMsg();
+     985         158 :   double height   = sh_height_.getMsg()->value;
+     986             : 
+     987         158 :   auto [odometry_x, odometry_y, odometry_z] = mrs_lib::getPosition(odometry);
+     988             : 
+     989         158 :   double odometry_heading = 0;
+     990             :   try {
+     991         158 :     odometry_heading = mrs_lib::getHeading(odometry);
+     992             :   }
+     993           0 :   catch (mrs_lib::AttitudeConverter::GetHeadingException& e) {
+     994           0 :     ROS_ERROR_THROTTLE(1.0, "[UavManager]: exception caught: '%s'", e.what());
+     995           0 :     return;
+     996             :   }
+     997             : 
+     998         158 :   if (height < _min_height_) {
+     999             : 
+    1000           0 :     ROS_WARN_THROTTLE(1.0, "[UavManager]: min height breached: %.2f < %.2f, triggering safety goto", height, _min_height_);
+    1001             : 
+    1002           0 :     mrs_msgs::ReferenceStamped reference_out;
+    1003           0 :     reference_out.header.frame_id = odometry->header.frame_id;
+    1004           0 :     reference_out.header.stamp    = ros::Time::now();
+    1005             : 
+    1006           0 :     reference_out.reference.position.x = odometry_x;
+    1007           0 :     reference_out.reference.position.y = odometry_y;
+    1008           0 :     reference_out.reference.position.z = odometry_z + ((_min_height_ + _min_height_offset_) - height);
+    1009             : 
+    1010           0 :     reference_out.reference.heading = odometry_heading;
+    1011             : 
+    1012           0 :     setControlCallbacksSrv(false);
+    1013             : 
+    1014           0 :     bool success = emergencyReferenceSrv(reference_out);
+    1015             : 
+    1016           0 :     if (success) {
+    1017             : 
+    1018           0 :       ROS_INFO("[UavManager]: ascending");
+    1019             : 
+    1020           0 :       fixing_min_height_ = true;
+    1021             : 
+    1022             :     } else {
+    1023             : 
+    1024           0 :       ROS_ERROR_THROTTLE(1.0, "[UavManager]: could not ascend");
+    1025             : 
+    1026           0 :       setControlCallbacksSrv(true);
+    1027             :     }
+    1028             :   }
+    1029             : 
+    1030         158 :   if (fixing_min_height_ && height > _min_height_) {
+    1031             : 
+    1032           0 :     setControlCallbacksSrv(true);
+    1033             : 
+    1034           0 :     ROS_WARN_THROTTLE(1.0, "[UavManager]: safe height reached");
+    1035             : 
+    1036           0 :     fixing_min_height_ = false;
+    1037             :   }
+    1038             : }
+    1039             : 
+    1040             : //}
+    1041             : 
+    1042             : /* //{ timerFlightTime() */
+    1043             : 
+    1044           5 : void UavManager::timerFlightTime(const ros::TimerEvent& event) {
+    1045             : 
+    1046           5 :   if (!is_initialized_)
+    1047           0 :     return;
+    1048             : 
+    1049          15 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerFlightTime", _flighttime_timer_rate_, 0.1, event);
+    1050          15 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::timerFlightTime", scope_timer_logger_, scope_timer_enabled_);
+    1051             : 
+    1052           5 :   auto flighttime = mrs_lib::get_mutexed(mutex_flighttime_, flighttime_);
+    1053             : 
+    1054           5 :   flighttime += 1.0 / _flighttime_timer_rate_;
+    1055             : 
+    1056           5 :   mrs_msgs::Float64 flight_time;
+    1057           5 :   flight_time.value = flighttime;
+    1058             : 
+    1059             :   // if enabled, start the timer for measuring the flight time
+    1060           5 :   if (_flighttime_timer_enabled_) {
+    1061             : 
+    1062           0 :     if (flighttime > _flighttime_max_time_) {
+    1063             : 
+    1064           0 :       flighttime = 0;
+    1065           0 :       timer_flighttime_.stop();
+    1066             : 
+    1067           0 :       ROS_INFO("[UavManager]: max flight time reached, landing");
+    1068             : 
+    1069           0 :       landImpl();
+    1070             :     }
+    1071             :   }
+    1072             : 
+    1073           5 :   mrs_lib::set_mutexed(mutex_flighttime_, flighttime, flighttime_);
+    1074             : }
+    1075             : 
+    1076             : //}
+    1077             : 
+    1078             : /* //{ timerMaxthrottle() */
+    1079             : 
+    1080        3357 : void UavManager::timerMaxthrottle(const ros::TimerEvent& event) {
+    1081             : 
+    1082        3357 :   if (!is_initialized_)
+    1083         931 :     return;
+    1084             : 
+    1085        3357 :   if (!sh_throttle_.hasMsg() || (ros::Time::now() - sh_throttle_.lastMsgTime()).toSec() > 1.0) {
+    1086         931 :     return;
+    1087             :   }
+    1088             : 
+    1089        2426 :   ROS_INFO_ONCE("[UavManager]: max throttle timer spinning");
+    1090             : 
+    1091        7278 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerMaxthrottle", _maxthrottle_timer_rate_, 0.03, event);
+    1092        7278 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::timerMaxthrottle", scope_timer_logger_, scope_timer_enabled_);
+    1093             : 
+    1094        2426 :   auto desired_throttle = sh_throttle_.getMsg()->data;
+    1095             : 
+    1096        2426 :   if (desired_throttle >= _maxthrottle_max_throttle_) {
+    1097             : 
+    1098           0 :     if (!maxthrottle_above_threshold_) {
+    1099             : 
+    1100           0 :       maxthrottle_first_time_      = ros::Time::now();
+    1101           0 :       maxthrottle_above_threshold_ = true;
+    1102           0 :       ROS_WARN_THROTTLE(1.0, "[UavManager]: max throttle exceeded threshold (%.2f/%.2f)", desired_throttle, _maxthrottle_max_throttle_);
+    1103             : 
+    1104             :     } else {
+    1105             : 
+    1106           0 :       ROS_WARN_THROTTLE(0.1, "[UavManager]: throttle over threshold (%.2f/%.2f) for %.2f s", desired_throttle, _maxthrottle_max_throttle_,
+    1107             :                         (ros::Time::now() - maxthrottle_first_time_).toSec());
+    1108             :     }
+    1109             : 
+    1110             :   } else {
+    1111             : 
+    1112        2426 :     maxthrottle_above_threshold_ = false;
+    1113             :   }
+    1114             : 
+    1115        2426 :   if (maxthrottle_above_threshold_ && (ros::Time::now() - maxthrottle_first_time_).toSec() > _maxthrottle_ungrip_timeout_) {
+    1116             : 
+    1117           0 :     ROS_WARN_THROTTLE(1.0, "[UavManager]: throttle over threshold (%.2f/%.2f) for more than %.2f s, ungripping payload", desired_throttle,
+    1118             :                       _maxthrottle_max_throttle_, _maxthrottle_ungrip_timeout_);
+    1119             : 
+    1120           0 :     ungripSrv();
+    1121             :   }
+    1122             : 
+    1123        2426 :   if (maxthrottle_above_threshold_ && (ros::Time::now() - maxthrottle_first_time_).toSec() > _maxthrottle_eland_timeout_) {
+    1124             : 
+    1125           0 :     timer_maxthrottle_.stop();
+    1126             : 
+    1127           0 :     ROS_ERROR_THROTTLE(1.0, "[UavManager]: throttle over threshold (%.2f/%.2f) for more than %.2f s, calling for emergency landing", desired_throttle,
+    1128             :                        _maxthrottle_max_throttle_, _maxthrottle_eland_timeout_);
+    1129             : 
+    1130           0 :     elandSrv();
+    1131             :   }
+    1132             : }
+    1133             : 
+    1134             : //}
+    1135             : 
+    1136             : /* //{ timerDiagnostics() */
+    1137             : 
+    1138         108 : void UavManager::timerDiagnostics(const ros::TimerEvent& event) {
+    1139             : 
+    1140         108 :   if (!is_initialized_)
+    1141           0 :     return;
+    1142             : 
+    1143         324 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("timerDiagnostics", _maxthrottle_timer_rate_, 0.03, event);
+    1144         324 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::timerDiagnostics", scope_timer_logger_, scope_timer_enabled_);
+    1145             : 
+    1146         108 :   bool got_gps_est = false;
+    1147         108 :   bool got_rtk_est = false;
+    1148             : 
+    1149         108 :   if (sh_estimation_diagnostics_.hasMsg()) {  // get current position in lat-lon
+    1150             : 
+    1151         176 :     auto                     estimation_diag  = sh_estimation_diagnostics_.getMsg();
+    1152          88 :     std::vector<std::string> state_estimators = estimation_diag.get()->switchable_state_estimators;
+    1153             : 
+    1154         176 :     got_gps_est = std::find(state_estimators.begin(), state_estimators.end(), "gps_garmin") != state_estimators.end() ||
+    1155          88 :                   std::find(state_estimators.begin(), state_estimators.end(), "gps_baro") != state_estimators.end();
+    1156          88 :     got_rtk_est = std::find(state_estimators.begin(), state_estimators.end(), "rtk") != state_estimators.end();
+    1157             :   }
+    1158             : 
+    1159         216 :   mrs_msgs::UavManagerDiagnostics diag;
+    1160             : 
+    1161         108 :   diag.stamp    = ros::Time::now();
+    1162         108 :   diag.uav_name = _uav_name_;
+    1163             : 
+    1164         108 :   auto flighttime = mrs_lib::get_mutexed(mutex_flighttime_, flighttime_);
+    1165             : 
+    1166             :   // fill in the acumulated flight time
+    1167         108 :   diag.flight_time = flighttime;
+    1168             : 
+    1169         108 :   if (sh_odometry_.hasMsg()) {  // get current position in lat-lon
+    1170             : 
+    1171          89 :     if (got_gps_est || got_rtk_est) {
+    1172             : 
+    1173          94 :       nav_msgs::Odometry odom = *sh_odometry_.getMsg();
+    1174             : 
+    1175          94 :       geometry_msgs::PoseStamped uav_pose;
+    1176          47 :       uav_pose.pose = mrs_lib::getPose(odom);
+    1177             : 
+    1178         141 :       auto res = transformer_->transformSingle(uav_pose, "latlon_origin");
+    1179             : 
+    1180          47 :       if (res) {
+    1181          47 :         diag.cur_latitude  = res.value().pose.position.x;
+    1182          47 :         diag.cur_longitude = res.value().pose.position.y;
+    1183             :       }
+    1184             :     }
+    1185             :   }
+    1186             : 
+    1187         108 :   if (takeoff_successful_) {
+    1188             : 
+    1189           5 :     if (got_gps_est || got_rtk_est) {
+    1190             : 
+    1191          10 :       auto land_there_reference = mrs_lib::get_mutexed(mutex_land_there_reference_, land_there_reference_);
+    1192             : 
+    1193          15 :       auto res = transformer_->transformSingle(land_there_reference, "latlon_origin");
+    1194             : 
+    1195           5 :       if (res) {
+    1196           5 :         diag.home_latitude  = res.value().reference.position.x;
+    1197           5 :         diag.home_longitude = res.value().reference.position.y;
+    1198             :       }
+    1199             :     }
+    1200             :   }
+    1201             : 
+    1202         108 :   ph_diag_.publish(diag);
+    1203             : }
+    1204             : 
+    1205             : //}
+    1206             : 
+    1207             : /* //{ timerMidairActivation() */
+    1208             : 
+    1209           6 : void UavManager::timerMidairActivation([[maybe_unused]] const ros::TimerEvent& event) {
+    1210             : 
+    1211           6 :   if (!is_initialized_)
+    1212           0 :     return;
+    1213             : 
+    1214           6 :   ROS_INFO_THROTTLE(0.1, "[UavManager]: waiting for OFFBOARD");
+    1215             : 
+    1216           6 :   if (sh_hw_api_status_.getMsg()->offboard) {
+    1217             : 
+    1218           6 :     ROS_INFO("[UavManager]: OFFBOARD detected");
+    1219             : 
+    1220           6 :     setOdometryCallbacksSrv(true);
+    1221             : 
+    1222             :     {
+    1223           6 :       bool controller_switched = switchControllerSrv(_midair_activation_after_controller_);
+    1224             : 
+    1225           6 :       if (!controller_switched) {
+    1226             : 
+    1227           0 :         ROS_ERROR("[UavManager]: could not activate '%s'", _midair_activation_after_controller_.c_str());
+    1228             : 
+    1229           0 :         ehoverSrv();
+    1230             : 
+    1231           0 :         timer_midair_activation_.stop();
+    1232             : 
+    1233           0 :         return;
+    1234             :       }
+    1235             :     }
+    1236             : 
+    1237             :     {
+    1238           6 :       bool tracker_switched = switchTrackerSrv(_midair_activation_after_tracker_);
+    1239             : 
+    1240           6 :       if (!tracker_switched) {
+    1241             : 
+    1242           0 :         ROS_ERROR("[UavManager]: could not activate '%s'", _midair_activation_after_tracker_.c_str());
+    1243             : 
+    1244           0 :         ehoverSrv();
+    1245             : 
+    1246           0 :         timer_midair_activation_.stop();
+    1247             : 
+    1248           0 :         return;
+    1249             :       }
+    1250             :     }
+    1251             : 
+    1252           6 :     timer_midair_activation_.stop();
+    1253             : 
+    1254           6 :     return;
+    1255             :   }
+    1256             : 
+    1257           0 :   if ((ros::Time::now() - midair_activation_started_).toSec() > 0.5) {
+    1258             : 
+    1259           0 :     ROS_ERROR("[UavManager]: waiting for OFFBOARD timeouted, reverting");
+    1260             : 
+    1261           0 :     toggleControlOutput(false);
+    1262             : 
+    1263           0 :     timer_midair_activation_.stop();
+    1264             : 
+    1265           0 :     return;
+    1266             :   }
+    1267             : }
+    1268             : 
+    1269             : //}
+    1270             : 
+    1271             : // --------------------------------------------------------------
+    1272             : // |                          callbacks                         |
+    1273             : // --------------------------------------------------------------
+    1274             : 
+    1275             : // | --------------------- topic callbacks -------------------- |
+    1276             : 
+    1277             : /* //{ callbackHwApiGNSS() */
+    1278             : 
+    1279        5497 : void UavManager::callbackHwApiGNSS(const sensor_msgs::NavSatFix::ConstPtr msg) {
+    1280             : 
+    1281        5497 :   if (!is_initialized_)
+    1282           4 :     return;
+    1283             : 
+    1284       16479 :   mrs_lib::Routine    profiler_routine = profiler_.createRoutine("callbackHwApiGNSS");
+    1285       16479 :   mrs_lib::ScopeTimer timer            = mrs_lib::ScopeTimer("UavManager::callbackHwApiGNSS", scope_timer_logger_, scope_timer_enabled_);
+    1286             : 
+    1287        5493 :   transformer_->setLatLon(msg->latitude, msg->longitude);
+    1288             : }
+    1289             : 
+    1290             : //}
+    1291             : 
+    1292             : /* //{ callbackOdometry() */
+    1293             : 
+    1294        8944 : void UavManager::callbackOdometry(const nav_msgs::Odometry::ConstPtr msg) {
+    1295             : 
+    1296        8944 :   if (!is_initialized_)
+    1297           0 :     return;
+    1298             : 
+    1299        8944 :   transformer_->setDefaultFrame(msg->header.frame_id);
+    1300             : }
+    1301             : 
+    1302             : //}
+    1303             : 
+    1304             : // | -------------------- service callbacks ------------------- |
+    1305             : 
+    1306             : /* //{ callbackTakeoff() */
+    1307             : 
+    1308           1 : bool UavManager::callbackTakeoff([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    1309             : 
+    1310           1 :   if (!is_initialized_)
+    1311           0 :     return false;
+    1312             : 
+    1313           1 :   ROS_INFO("[UavManager]: takeoff called by service");
+    1314             : 
+    1315             :   /* preconditions //{ */
+    1316             : 
+    1317             :   {
+    1318           1 :     std::stringstream ss;
+    1319             : 
+    1320           1 :     if (!sh_odometry_.hasMsg()) {
+    1321           0 :       ss << "can not takeoff, missing odometry!";
+    1322           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1323           0 :       res.message = ss.str();
+    1324           0 :       res.success = false;
+    1325           0 :       return true;
+    1326             :     }
+    1327             : 
+    1328           1 :     if (!sh_hw_api_status_.hasMsg() || (ros::Time::now() - sh_hw_api_status_.lastMsgTime()).toSec() > 5.0) {
+    1329           0 :       ss << "can not takeoff, missing HW API status!";
+    1330           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1331           0 :       res.message = ss.str();
+    1332           0 :       res.success = false;
+    1333           0 :       return true;
+    1334             :     }
+    1335             : 
+    1336           1 :     if (!sh_hw_api_status_.getMsg()->armed) {
+    1337           0 :       ss << "can not takeoff, UAV not armed!";
+    1338           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1339           0 :       res.message = ss.str();
+    1340           0 :       res.success = false;
+    1341           0 :       return true;
+    1342             :     }
+    1343             : 
+    1344           1 :     if (!sh_hw_api_status_.getMsg()->offboard) {
+    1345           0 :       ss << "can not takeoff, UAV not in offboard mode!";
+    1346           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1347           0 :       res.message = ss.str();
+    1348           0 :       res.success = false;
+    1349           0 :       return true;
+    1350             :     }
+    1351             : 
+    1352             :     {
+    1353           1 :       if (!sh_control_manager_diag_.hasMsg() && (ros::Time::now() - sh_control_manager_diag_.lastMsgTime()).toSec() > 5.0) {
+    1354           0 :         ss << "can not takeoff, missing control manager diagnostics!";
+    1355           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1356           0 :         res.message = ss.str();
+    1357           0 :         res.success = false;
+    1358           0 :         return true;
+    1359             :       }
+    1360             : 
+    1361           1 :       if (_null_tracker_name_ != sh_control_manager_diag_.getMsg()->active_tracker) {
+    1362           0 :         ss << "can not takeoff, need '" << _null_tracker_name_ << "' to be active!";
+    1363           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1364           0 :         res.message = ss.str();
+    1365           0 :         res.success = false;
+    1366           0 :         return true;
+    1367             :       }
+    1368             :     }
+    1369             : 
+    1370           1 :     if (!sh_controller_diagnostics_.hasMsg()) {
+    1371           0 :       ss << "can not takeoff, missing controller diagnostics!";
+    1372           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1373           0 :       res.message = ss.str();
+    1374           0 :       res.success = false;
+    1375           0 :       return true;
+    1376             :     }
+    1377             : 
+    1378           1 :     if (_gain_manager_required_ && (ros::Time::now() - sh_gains_diag_.lastMsgTime()).toSec() > 5.0) {
+    1379           0 :       ss << "can not takeoff, GainManager is not running!";
+    1380           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1381           0 :       res.message = ss.str();
+    1382           0 :       res.success = false;
+    1383           0 :       return true;
+    1384             :     }
+    1385             : 
+    1386           1 :     if (_constraint_manager_required_ && (ros::Time::now() - sh_constraints_diag_.lastMsgTime()).toSec() > 5.0) {
+    1387           0 :       ss << "can not takeoff, ConstraintManager is not running!";
+    1388           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1389           0 :       res.message = ss.str();
+    1390           0 :       res.success = false;
+    1391           0 :       return true;
+    1392             :     }
+    1393             : 
+    1394           1 :     if (!sh_control_manager_diag_.getMsg()->output_enabled) {
+    1395             : 
+    1396           0 :       ss << "can not takeoff, Control Manager's output is disabled!";
+    1397           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1398           0 :       res.message = ss.str();
+    1399           0 :       res.success = false;
+    1400           0 :       return true;
+    1401             :     }
+    1402             : 
+    1403           1 :     if (number_of_takeoffs_ > 0) {
+    1404             : 
+    1405           0 :       auto last_mass_difference = mrs_lib::get_mutexed(mutex_last_mass_difference_, last_mass_difference_);
+    1406             : 
+    1407           0 :       if (last_mass_difference > 1.0) {
+    1408             : 
+    1409           0 :         ss << std::setprecision(2);
+    1410           0 :         ss << "can not takeoff, estimated mass difference is too large: " << _null_tracker_name_ << "!";
+    1411           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1412           0 :         res.message = ss.str();
+    1413           0 :         res.success = false;
+    1414           0 :         return true;
+    1415             :       }
+    1416             :     }
+    1417             :   }
+    1418             : 
+    1419             :   //}
+    1420             : 
+    1421           2 :   auto control_manager_diagnostics = sh_control_manager_diag_.getMsg();
+    1422           2 :   auto odometry                    = sh_odometry_.getMsg();
+    1423           1 :   auto [odom_x, odom_y, odom_z]    = mrs_lib::getPosition(sh_odometry_.getMsg());
+    1424             : 
+    1425             :   double odom_heading;
+    1426             :   try {
+    1427           1 :     odom_heading = mrs_lib::getHeading(sh_odometry_.getMsg());
+    1428             :   }
+    1429           0 :   catch (mrs_lib::AttitudeConverter::GetHeadingException& e) {
+    1430           0 :     ROS_ERROR_THROTTLE(1.0, "[UavManager]: exception caught: '%s'", e.what());
+    1431             : 
+    1432           0 :     std::stringstream ss;
+    1433           0 :     ss << "could not calculate current heading";
+    1434           0 :     ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1435           0 :     res.message = ss.str();
+    1436           0 :     res.success = false;
+    1437           0 :     return true;
+    1438             :   }
+    1439             : 
+    1440           1 :   ROS_INFO("[UavManager]: taking off");
+    1441             : 
+    1442           1 :   setOdometryCallbacksSrv(false);
+    1443             : 
+    1444             :   // activating the takeoff controller
+    1445             :   {
+    1446           1 :     std::string old_controller      = sh_control_manager_diag_.getMsg()->active_controller;
+    1447           1 :     bool        controller_switched = switchControllerSrv(_takeoff_controller_name_);
+    1448             : 
+    1449             :     // if it fails, activate back the old controller
+    1450             :     // this is no big deal since the control outputs are not used
+    1451             :     // until NullTracker is active
+    1452           1 :     if (!controller_switched) {
+    1453             : 
+    1454           0 :       std::stringstream ss;
+    1455           0 :       ss << "could not activate '" << _takeoff_controller_name_ << "' for takeoff";
+    1456           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1457           0 :       res.success = false;
+    1458           0 :       res.message = ss.str();
+    1459             : 
+    1460           0 :       switchControllerSrv(old_controller);
+    1461             : 
+    1462           0 :       return true;
+    1463             :     }
+    1464             :   }
+    1465             : 
+    1466             :   // activate the takeoff tracker
+    1467             :   {
+    1468           1 :     std::string old_tracker      = sh_control_manager_diag_.getMsg()->active_tracker;
+    1469           1 :     bool        tracker_switched = switchTrackerSrv(_takeoff_tracker_name_);
+    1470             : 
+    1471             :     // if it fails, activate back the old tracker
+    1472           1 :     if (!tracker_switched) {
+    1473             : 
+    1474           0 :       std::stringstream ss;
+    1475           0 :       ss << "could not activate '" << _takeoff_tracker_name_ << "' for takeoff";
+    1476           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1477           0 :       res.success = false;
+    1478           0 :       res.message = ss.str();
+    1479             : 
+    1480           0 :       switchTrackerSrv(old_tracker);
+    1481             : 
+    1482           0 :       return true;
+    1483             :     }
+    1484             :   }
+    1485             : 
+    1486             :   // let's sleep before calling take off.. the motors are rumping-up anyway
+    1487             :   // this solves on-time-happening race condition in the landoff tracker
+    1488           1 :   ros::Duration(0.3).sleep();
+    1489             : 
+    1490             :   // now the takeoff tracker and controller are active
+    1491             :   // the UAV is basically hovering on the ground
+    1492             :   // (the controller is probably rumping up the throttle now)
+    1493             : 
+    1494             :   // call the takeoff service at the takeoff tracker
+    1495             :   {
+    1496           1 :     bool takeoff_successful = takeoffSrv();
+    1497             : 
+    1498             :     // if the takeoff was not successful, switch to NullTracker
+    1499           1 :     if (takeoff_successful) {
+    1500             : 
+    1501             :       // save the current spot for later landing
+    1502             :       {
+    1503           1 :         std::scoped_lock lock(mutex_land_there_reference_);
+    1504             : 
+    1505           1 :         land_there_reference_.header               = odometry->header;
+    1506           1 :         land_there_reference_.reference.position.x = odom_x;
+    1507           1 :         land_there_reference_.reference.position.y = odom_y;
+    1508           1 :         land_there_reference_.reference.position.z = odom_z;
+    1509           1 :         land_there_reference_.reference.heading    = odom_heading;
+    1510             :       }
+    1511             : 
+    1512           1 :       timer_flighttime_.start();
+    1513             : 
+    1514           2 :       std::stringstream ss;
+    1515           1 :       ss << "taking off";
+    1516           1 :       res.success = true;
+    1517           1 :       res.message = ss.str();
+    1518           1 :       ROS_INFO_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1519             : 
+    1520           1 :       takingoff_ = true;
+    1521           1 :       number_of_takeoffs_++;
+    1522           1 :       waiting_for_takeoff_ = true;
+    1523             : 
+    1524             :       // start the takeoff timer
+    1525           1 :       timer_takeoff_.start();
+    1526             : 
+    1527           1 :       takeoff_successful_ = takeoff_successful;
+    1528             : 
+    1529             :     } else {
+    1530             : 
+    1531           0 :       std::stringstream ss;
+    1532           0 :       ss << "takeoff was not successful";
+    1533           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1534           0 :       res.success = false;
+    1535           0 :       res.message = ss.str();
+    1536             : 
+    1537             :       // if the call for takeoff fails, call for emergency landing
+    1538           0 :       elandSrv();
+    1539             :     }
+    1540             :   }
+    1541             : 
+    1542           1 :   return true;
+    1543             : }
+    1544             : 
+    1545             : //}
+    1546             : 
+    1547             : /* //{ callbackLand() */
+    1548             : 
+    1549           1 : bool UavManager::callbackLand([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    1550             : 
+    1551           1 :   if (!is_initialized_)
+    1552           0 :     return false;
+    1553             : 
+    1554           1 :   ROS_INFO("[UavManager]: land called by service");
+    1555             : 
+    1556             :   /* preconditions //{ */
+    1557             : 
+    1558             :   {
+    1559           1 :     std::stringstream ss;
+    1560             : 
+    1561           1 :     if (!sh_odometry_.hasMsg()) {
+    1562           0 :       ss << "can not land, missing odometry!";
+    1563           0 :       res.message = ss.str();
+    1564           0 :       res.success = false;
+    1565           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1566           0 :       return true;
+    1567             :     }
+    1568             : 
+    1569             :     {
+    1570           1 :       if (!sh_control_manager_diag_.hasMsg()) {
+    1571           0 :         ss << "can not land, missing control manager diagnostics!";
+    1572           0 :         res.message = ss.str();
+    1573           0 :         res.success = false;
+    1574           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1575           0 :         return true;
+    1576             :       }
+    1577             : 
+    1578           1 :       if (_null_tracker_name_ == sh_control_manager_diag_.getMsg()->active_tracker) {
+    1579           0 :         ss << "can not land, '" << _null_tracker_name_ << "' is active!";
+    1580           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1581           0 :         res.message = ss.str();
+    1582           0 :         res.success = false;
+    1583           0 :         return true;
+    1584             :       }
+    1585             :     }
+    1586             : 
+    1587           1 :     if (!sh_controller_diagnostics_.hasMsg()) {
+    1588           0 :       ss << "can not land, missing controller diagnostics!";
+    1589           0 :       res.message = ss.str();
+    1590           0 :       res.success = false;
+    1591           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1592           0 :       return true;
+    1593             :     }
+    1594             : 
+    1595           1 :     if (!sh_tracker_cmd_.hasMsg()) {
+    1596           0 :       ss << "can not land, missing position cmd!";
+    1597           0 :       res.message = ss.str();
+    1598           0 :       res.success = false;
+    1599           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1600           0 :       return true;
+    1601             :     }
+    1602             :   }
+    1603             : 
+    1604             :   //}
+    1605             : 
+    1606           1 :   auto [success, message] = landWithDescendImpl();
+    1607             : 
+    1608           1 :   res.message = message;
+    1609           1 :   res.success = success;
+    1610             : 
+    1611           1 :   return true;
+    1612             : }
+    1613             : 
+    1614             : //}
+    1615             : 
+    1616             : /* //{ callbackLandHome() */
+    1617             : 
+    1618           0 : bool UavManager::callbackLandHome([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    1619             : 
+    1620           0 :   if (!is_initialized_)
+    1621           0 :     return false;
+    1622             : 
+    1623           0 :   ROS_INFO("[UavManager]: land home called by service");
+    1624             : 
+    1625             :   /* preconditions //{ */
+    1626             : 
+    1627             :   {
+    1628           0 :     std::stringstream ss;
+    1629             : 
+    1630           0 :     if (number_of_takeoffs_ == 0) {
+    1631           0 :       ss << "can not land home, did not takeoff before!";
+    1632           0 :       res.message = ss.str();
+    1633           0 :       res.success = false;
+    1634           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1635           0 :       return true;
+    1636             :     }
+    1637             : 
+    1638           0 :     if (!sh_odometry_.hasMsg()) {
+    1639           0 :       ss << "can not land, missing odometry!";
+    1640           0 :       res.message = ss.str();
+    1641           0 :       res.success = false;
+    1642           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1643           0 :       return true;
+    1644             :     }
+    1645             : 
+    1646             :     {
+    1647           0 :       if (!sh_control_manager_diag_.hasMsg()) {
+    1648           0 :         ss << "can not land, missing tracker status!";
+    1649           0 :         res.message = ss.str();
+    1650           0 :         res.success = false;
+    1651           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1652           0 :         return true;
+    1653             :       }
+    1654             : 
+    1655           0 :       if (_null_tracker_name_ == sh_control_manager_diag_.getMsg()->active_tracker) {
+    1656           0 :         ss << "can not land, '" << _null_tracker_name_ << "' is active!";
+    1657           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1658           0 :         res.message = ss.str();
+    1659           0 :         res.success = false;
+    1660           0 :         return true;
+    1661             :       }
+    1662             :     }
+    1663             : 
+    1664           0 :     if (!sh_controller_diagnostics_.hasMsg()) {
+    1665           0 :       ss << "can not land, missing controller diagnostics command!";
+    1666           0 :       res.message = ss.str();
+    1667           0 :       res.success = false;
+    1668           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1669           0 :       return true;
+    1670             :     }
+    1671             : 
+    1672           0 :     if (!sh_tracker_cmd_.hasMsg()) {
+    1673           0 :       ss << "can not land, missing position cmd!";
+    1674           0 :       res.message = ss.str();
+    1675           0 :       res.success = false;
+    1676           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1677           0 :       return true;
+    1678             :     }
+    1679             : 
+    1680           0 :     if (fixing_max_height_) {
+    1681           0 :       ss << "can not land, descedning to safe height!";
+    1682           0 :       res.message = ss.str();
+    1683           0 :       res.success = false;
+    1684           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1685           0 :       return true;
+    1686             :     }
+    1687             : 
+    1688           0 :     if (current_state_landing_ != IDLE_STATE) {
+    1689           0 :       ss << "can not land, already landing!";
+    1690           0 :       res.message = ss.str();
+    1691           0 :       res.success = false;
+    1692           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1693           0 :       return true;
+    1694             :     }
+    1695             :   }
+    1696             : 
+    1697             :   //}
+    1698             : 
+    1699           0 :   ungripSrv();
+    1700             : 
+    1701           0 :   mrs_msgs::ReferenceStamped reference_out;
+    1702             : 
+    1703             :   {
+    1704           0 :     std::scoped_lock lock(mutex_land_there_reference_);
+    1705             : 
+    1706             :     // get the current altitude in land_there_reference_.header.frame_id;
+    1707           0 :     geometry_msgs::PoseStamped current_pose;
+    1708           0 :     current_pose.header.stamp     = ros::Time::now();
+    1709           0 :     current_pose.header.frame_id  = _uav_name_ + "/fcu";
+    1710           0 :     current_pose.pose.position.x  = 0;
+    1711           0 :     current_pose.pose.position.y  = 0;
+    1712           0 :     current_pose.pose.position.z  = 0;
+    1713           0 :     current_pose.pose.orientation = mrs_lib::AttitudeConverter(0, 0, 0);
+    1714             : 
+    1715           0 :     auto response = transformer_->transformSingle(current_pose, land_there_reference_.header.frame_id);
+    1716             : 
+    1717           0 :     if (response) {
+    1718             : 
+    1719           0 :       land_there_reference_.reference.position.z = response.value().pose.position.z;
+    1720           0 :       ROS_DEBUG("[UavManager]: current altitude is %.2f m", land_there_reference_.reference.position.z);
+    1721             : 
+    1722             :     } else {
+    1723             : 
+    1724           0 :       std::stringstream ss;
+    1725           0 :       ss << "could not transform current height to " << land_there_reference_.header.frame_id;
+    1726           0 :       ROS_ERROR_STREAM("[UavManager]: " << ss.str());
+    1727             : 
+    1728           0 :       res.success = false;
+    1729           0 :       res.message = ss.str();
+    1730           0 :       return true;
+    1731             :     }
+    1732             : 
+    1733           0 :     reference_out.header.frame_id = land_there_reference_.header.frame_id;
+    1734           0 :     reference_out.header.stamp    = ros::Time::now();
+    1735           0 :     reference_out.reference       = land_there_reference_.reference;
+    1736             :   }
+    1737             : 
+    1738           0 :   bool service_success = emergencyReferenceSrv(reference_out);
+    1739             : 
+    1740           0 :   if (service_success) {
+    1741             : 
+    1742           0 :     std::stringstream ss;
+    1743           0 :     ss << "flying home for landing";
+    1744           0 :     ROS_INFO_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1745             : 
+    1746           0 :     res.success = true;
+    1747           0 :     res.message = ss.str();
+    1748             : 
+    1749             :     // stop the eventual takeoff
+    1750           0 :     waiting_for_takeoff_ = false;
+    1751           0 :     takingoff_           = false;
+    1752           0 :     timer_takeoff_.stop();
+    1753             : 
+    1754           0 :     throttle_under_threshold_          = false;
+    1755           0 :     throttle_mass_estimate_first_time_ = ros::Time(0);
+    1756             : 
+    1757           0 :     changeLandingState(FLY_THERE_STATE);
+    1758             : 
+    1759           0 :     timer_landing_.start();
+    1760             : 
+    1761             :   } else {
+    1762             : 
+    1763           0 :     std::stringstream ss;
+    1764           0 :     ss << "can not fly home for landing";
+    1765           0 :     ROS_ERROR_STREAM("[UavManager]: " << ss.str());
+    1766             : 
+    1767           0 :     res.success = false;
+    1768           0 :     res.message = ss.str();
+    1769             :   }
+    1770             : 
+    1771           0 :   return true;
+    1772             : }
+    1773             : 
+    1774             : //}
+    1775             : 
+    1776             : /* //{ callbackLandThere() */
+    1777             : 
+    1778           0 : bool UavManager::callbackLandThere(mrs_msgs::ReferenceStampedSrv::Request& req, mrs_msgs::ReferenceStampedSrv::Response& res) {
+    1779             : 
+    1780           0 :   if (!is_initialized_)
+    1781           0 :     return false;
+    1782             : 
+    1783           0 :   ROS_INFO("[UavManager]: land there called by service");
+    1784             : 
+    1785             :   /* preconditions //{ */
+    1786             : 
+    1787             :   {
+    1788           0 :     std::stringstream ss;
+    1789             : 
+    1790           0 :     if (!sh_odometry_.hasMsg()) {
+    1791           0 :       ss << "can not land, missing odometry!";
+    1792           0 :       res.message = ss.str();
+    1793           0 :       res.success = false;
+    1794           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1795           0 :       return true;
+    1796             :     }
+    1797             : 
+    1798             :     {
+    1799           0 :       if (!sh_control_manager_diag_.hasMsg()) {
+    1800           0 :         ss << "can not land, missing tracker status!";
+    1801           0 :         res.message = ss.str();
+    1802           0 :         res.success = false;
+    1803           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1804           0 :         return true;
+    1805             :       }
+    1806             : 
+    1807           0 :       if (_null_tracker_name_ == sh_control_manager_diag_.getMsg()->active_tracker) {
+    1808           0 :         ss << "can not land, '" << _null_tracker_name_ << "' is active!";
+    1809           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1810           0 :         res.message = ss.str();
+    1811           0 :         res.success = false;
+    1812           0 :         return true;
+    1813             :       }
+    1814             :     }
+    1815             : 
+    1816           0 :     if (!sh_controller_diagnostics_.hasMsg()) {
+    1817           0 :       ss << "can not land, missing controller diagnostics!";
+    1818           0 :       res.message = ss.str();
+    1819           0 :       res.success = false;
+    1820           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1821           0 :       return true;
+    1822             :     }
+    1823             : 
+    1824           0 :     if (!sh_tracker_cmd_.hasMsg()) {
+    1825           0 :       ss << "can not land, missing position cmd!";
+    1826           0 :       res.message = ss.str();
+    1827           0 :       res.success = false;
+    1828           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1829           0 :       return true;
+    1830             :     }
+    1831             : 
+    1832           0 :     if (fixing_max_height_) {
+    1833           0 :       ss << "can not land, descedning to safe height!";
+    1834           0 :       res.message = ss.str();
+    1835           0 :       res.success = false;
+    1836           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1837           0 :       return true;
+    1838             :     }
+    1839             :   }
+    1840             : 
+    1841             :   //}
+    1842             : 
+    1843           0 :   ungripSrv();
+    1844             : 
+    1845           0 :   mrs_msgs::ReferenceStamped reference_out;
+    1846             : 
+    1847             :   {
+    1848           0 :     std::scoped_lock lock(mutex_land_there_reference_);
+    1849             : 
+    1850           0 :     land_there_reference_.header    = req.header;
+    1851           0 :     land_there_reference_.reference = req.reference;
+    1852             : 
+    1853           0 :     reference_out.header.frame_id = land_there_reference_.header.frame_id;
+    1854           0 :     reference_out.header.stamp    = ros::Time::now();
+    1855           0 :     reference_out.reference       = land_there_reference_.reference;
+    1856             :   }
+    1857             : 
+    1858           0 :   bool service_success = emergencyReferenceSrv(reference_out);
+    1859             : 
+    1860           0 :   if (service_success) {
+    1861             : 
+    1862           0 :     std::stringstream ss;
+    1863           0 :     ss << "flying there for landing";
+    1864           0 :     ROS_INFO_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1865             : 
+    1866           0 :     res.success = true;
+    1867           0 :     res.message = ss.str();
+    1868             : 
+    1869             :     // stop the eventual takeoff
+    1870           0 :     waiting_for_takeoff_ = false;
+    1871           0 :     takingoff_           = false;
+    1872           0 :     timer_takeoff_.stop();
+    1873             : 
+    1874           0 :     throttle_under_threshold_          = false;
+    1875           0 :     throttle_mass_estimate_first_time_ = ros::Time(0);
+    1876             : 
+    1877           0 :     changeLandingState(FLY_THERE_STATE);
+    1878             : 
+    1879           0 :     timer_landing_.start();
+    1880             : 
+    1881             :   } else {
+    1882             : 
+    1883           0 :     std::stringstream ss;
+    1884           0 :     ss << "can not fly there for landing";
+    1885           0 :     ROS_ERROR_STREAM("[UavManager]: " << ss.str());
+    1886             : 
+    1887           0 :     res.success = false;
+    1888           0 :     res.message = ss.str();
+    1889             :   }
+    1890             : 
+    1891           0 :   return true;
+    1892             : }
+    1893             : 
+    1894             : //}
+    1895             : 
+    1896             : /* //{ callbackMidairActivation() */
+    1897             : 
+    1898           6 : bool UavManager::callbackMidairActivation([[maybe_unused]] std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res) {
+    1899             : 
+    1900           6 :   if (!is_initialized_)
+    1901           0 :     return false;
+    1902             : 
+    1903           6 :   ROS_INFO("[UavManager]: midair activation called by service");
+    1904             : 
+    1905             :   /* preconditions //{ */
+    1906             : 
+    1907             :   {
+    1908           6 :     std::stringstream ss;
+    1909             : 
+    1910           6 :     if (!sh_odometry_.hasMsg()) {
+    1911           0 :       ss << "can not activate, missing odometry!";
+    1912           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1913           0 :       res.message = ss.str();
+    1914           0 :       res.success = false;
+    1915           0 :       return true;
+    1916             :     }
+    1917             : 
+    1918           6 :     if (!sh_hw_api_status_.hasMsg() || (ros::Time::now() - sh_hw_api_status_.lastMsgTime()).toSec() > 5.0) {
+    1919           0 :       ss << "can not activate, missing HW API status!";
+    1920           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1921           0 :       res.message = ss.str();
+    1922           0 :       res.success = false;
+    1923           0 :       return true;
+    1924             :     }
+    1925             : 
+    1926           6 :     if (!sh_hw_api_status_.getMsg()->armed) {
+    1927           0 :       ss << "can not activate, UAV not armed!";
+    1928           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1929           0 :       res.message = ss.str();
+    1930           0 :       res.success = false;
+    1931           0 :       return true;
+    1932             :     }
+    1933             : 
+    1934           6 :     if (sh_hw_api_status_.getMsg()->offboard) {
+    1935           0 :       ss << "can not activate, UAV already in offboard mode!";
+    1936           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1937           0 :       res.message = ss.str();
+    1938           0 :       res.success = false;
+    1939           0 :       return true;
+    1940             :     }
+    1941             : 
+    1942             :     {
+    1943           6 :       if (!sh_control_manager_diag_.hasMsg()) {
+    1944           0 :         ss << "can not activate, missing control manager diagnostics!";
+    1945           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1946           0 :         res.message = ss.str();
+    1947           0 :         res.success = false;
+    1948           0 :         return true;
+    1949             :       }
+    1950             : 
+    1951           6 :       if (_null_tracker_name_ != sh_control_manager_diag_.getMsg()->active_tracker) {
+    1952           0 :         ss << "can not activate, need '" << _null_tracker_name_ << "' to be active!";
+    1953           0 :         ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1954           0 :         res.message = ss.str();
+    1955           0 :         res.success = false;
+    1956           0 :         return true;
+    1957             :       }
+    1958             :     }
+    1959             : 
+    1960           6 :     if (!sh_controller_diagnostics_.hasMsg()) {
+    1961           0 :       ss << "can not activate, missing controller diagnostics!";
+    1962           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1963           0 :       res.message = ss.str();
+    1964           0 :       res.success = false;
+    1965           0 :       return true;
+    1966             :     }
+    1967             : 
+    1968           6 :     if (_gain_manager_required_ && (ros::Time::now() - sh_gains_diag_.lastMsgTime()).toSec() > 5.0) {
+    1969           0 :       ss << "can not activate, GainManager is not running!";
+    1970           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1971           0 :       res.message = ss.str();
+    1972           0 :       res.success = false;
+    1973           0 :       return true;
+    1974             :     }
+    1975             : 
+    1976           6 :     if (_constraint_manager_required_ && (ros::Time::now() - sh_constraints_diag_.lastMsgTime()).toSec() > 5.0) {
+    1977           0 :       ss << "can not activate, ConstraintManager is not running!";
+    1978           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1979           0 :       res.message = ss.str();
+    1980           0 :       res.success = false;
+    1981           0 :       return true;
+    1982             :     }
+    1983             : 
+    1984           6 :     if (number_of_takeoffs_ > 0) {
+    1985           0 :       ss << "can not activate, we flew already!";
+    1986           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    1987           0 :       res.message = ss.str();
+    1988           0 :       res.success = false;
+    1989           0 :       return true;
+    1990             :     }
+    1991             :   }
+    1992             : 
+    1993             :   //}
+    1994             : 
+    1995           6 :   auto [success, message] = midairActivationImpl();
+    1996             : 
+    1997           6 :   res.message = message;
+    1998           6 :   res.success = success;
+    1999             : 
+    2000           6 :   return true;
+    2001             : }
+    2002             : 
+    2003             : //}
+    2004             : 
+    2005             : // | ------------------------ routines ------------------------ |
+    2006             : 
+    2007             : /* landImpl() //{ */
+    2008             : 
+    2009           1 : std::tuple<bool, std::string> UavManager::landImpl(void) {
+    2010             : 
+    2011             :   // activating the landing controller
+    2012             :   {
+    2013           1 :     std::string old_controller      = sh_control_manager_diag_.getMsg()->active_controller;
+    2014           1 :     bool        controller_switched = switchControllerSrv(_landing_controller_name_);
+    2015             : 
+    2016             :     // if it fails, activate eland
+    2017             :     // Tomas: I pressume that its more important to get the UAV to the ground rather than
+    2018             :     // just throw out error.
+    2019           1 :     if (!controller_switched) {
+    2020             : 
+    2021           0 :       std::stringstream ss;
+    2022           0 :       ss << "could not activate '" << _takeoff_controller_name_ << "' for landing";
+    2023           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2024             : 
+    2025           0 :       elandSrv();
+    2026             : 
+    2027           0 :       return std::tuple(false, ss.str());
+    2028             :     }
+    2029             :   }
+    2030             : 
+    2031             :   // activate the landing tracker
+    2032             :   {
+    2033           1 :     std::string old_tracker      = sh_control_manager_diag_.getMsg()->active_tracker;
+    2034           1 :     bool        tracker_switched = switchTrackerSrv(_landing_tracker_name_);
+    2035             : 
+    2036             :     // if it fails, activate eland
+    2037             :     // Tomas: I pressume that its more important to get the UAV to the ground rather than
+    2038             :     // just throw out error.
+    2039           1 :     if (!tracker_switched) {
+    2040             : 
+    2041           0 :       std::stringstream ss;
+    2042           0 :       ss << "could not activate '" << _takeoff_tracker_name_ << "' for landing";
+    2043           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2044             : 
+    2045           0 :       elandSrv();
+    2046             : 
+    2047           0 :       return std::tuple(false, ss.str());
+    2048             :     }
+    2049             :   }
+    2050             : 
+    2051             :   // call the landing service
+    2052             :   {
+    2053           1 :     bool land_successful = landSrv();
+    2054             : 
+    2055           1 :     if (land_successful) {
+    2056             : 
+    2057             :       // stop the eventual takeoff
+    2058           1 :       waiting_for_takeoff_ = false;
+    2059           1 :       takingoff_           = false;
+    2060           1 :       timer_takeoff_.stop();
+    2061             : 
+    2062             :       // stop counting the flight time
+    2063           1 :       timer_flighttime_.stop();
+    2064             : 
+    2065           2 :       auto controller_diagnostics = sh_controller_diagnostics_.getMsg();
+    2066             : 
+    2067             :       // remember the last valid mass estimated
+    2068             :       // used during subsequent takeoff
+    2069           1 :       if (controller_diagnostics->mass_estimator) {
+    2070           1 :         last_mass_difference_ = controller_diagnostics->mass_difference;
+    2071             :       }
+    2072             : 
+    2073           1 :       setOdometryCallbacksSrv(false);
+    2074             : 
+    2075           1 :       changeLandingState(LANDING_STATE);
+    2076             : 
+    2077           1 :       throttle_under_threshold_          = false;
+    2078           1 :       throttle_mass_estimate_first_time_ = ros::Time(0);
+    2079             : 
+    2080           1 :       timer_landing_.start();
+    2081             : 
+    2082           1 :       std::stringstream ss;
+    2083           1 :       ss << "landing initiated";
+    2084           1 :       ROS_INFO_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2085             : 
+    2086           1 :       return std::tuple(true, ss.str());
+    2087             : 
+    2088             :     } else {
+    2089             : 
+    2090           0 :       std::stringstream ss;
+    2091           0 :       ss << "could not land";
+    2092           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2093             : 
+    2094           0 :       elandSrv();
+    2095             : 
+    2096           0 :       return std::tuple(false, ss.str());
+    2097             :     }
+    2098             :   }
+    2099             : }
+    2100             : 
+    2101             : //}
+    2102             : 
+    2103             : /* landWithDescendImpl() //{ */
+    2104             : 
+    2105           1 : std::tuple<bool, std::string> UavManager::landWithDescendImpl(void) {
+    2106             : 
+    2107             :   // if the height information is available
+    2108           1 :   if (sh_height_.hasMsg()) {
+    2109             : 
+    2110           1 :     double height = sh_height_.getMsg()->value;
+    2111             : 
+    2112           1 :     if (height > 0 && height >= _landing_descend_height_ + 1.0) {
+    2113             : 
+    2114           0 :       auto odometry = sh_odometry_.getMsg();
+    2115             : 
+    2116           0 :       ungripSrv();
+    2117             : 
+    2118             :       {
+    2119           0 :         std::scoped_lock lock(mutex_land_there_reference_);
+    2120             : 
+    2121             :         // FOR FUTURE ME: Do not change this, we need it to be filled for the final check later
+    2122           0 :         land_there_reference_.header.frame_id      = "";
+    2123           0 :         land_there_reference_.header.stamp         = ros::Time::now();
+    2124           0 :         land_there_reference_.reference.position.x = odometry->pose.pose.position.x;
+    2125           0 :         land_there_reference_.reference.position.y = odometry->pose.pose.position.y;
+    2126           0 :         land_there_reference_.reference.position.z = odometry->pose.pose.position.z - (height - _landing_descend_height_);
+    2127           0 :         land_there_reference_.reference.heading    = mrs_lib::AttitudeConverter(odometry->pose.pose.orientation).getHeading();
+    2128             :       }
+    2129             : 
+    2130           0 :       bool service_success = emergencyReferenceSrv(land_there_reference_);
+    2131             : 
+    2132           0 :       if (service_success) {
+    2133             : 
+    2134           0 :         std::stringstream ss;
+    2135           0 :         ss << "flying down for landing";
+    2136           0 :         ROS_INFO_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2137             : 
+    2138             :         // stop the eventual takeoff
+    2139           0 :         waiting_for_takeoff_ = false;
+    2140           0 :         takingoff_           = false;
+    2141           0 :         timer_takeoff_.stop();
+    2142             : 
+    2143           0 :         changeLandingState(FLY_THERE_STATE);
+    2144             : 
+    2145           0 :         throttle_under_threshold_          = false;
+    2146           0 :         throttle_mass_estimate_first_time_ = ros::Time(0);
+    2147             : 
+    2148           0 :         timer_landing_.start();
+    2149             : 
+    2150           0 :         return std::tuple(true, ss.str());
+    2151             : 
+    2152             :       } else {
+    2153             : 
+    2154           0 :         std::stringstream ss;
+    2155           0 :         ss << "can not fly down for landing";
+    2156           0 :         ROS_ERROR_STREAM("[UavManager]: " << ss.str());
+    2157             :       }
+    2158             :     }
+    2159             :   }
+    2160             : 
+    2161           2 :   auto [success, message] = landImpl();
+    2162             : 
+    2163           1 :   return std::tuple(success, message);
+    2164             : }
+    2165             : 
+    2166             : //}
+    2167             : 
+    2168             : /* midairActivationImpl() //{ */
+    2169             : 
+    2170           6 : std::tuple<bool, std::string> UavManager::midairActivationImpl(void) {
+    2171             : 
+    2172             :   // 1. activate the mid-air activation controller
+    2173             :   // the controller will output hover-like control output
+    2174          12 :   std::string old_controller;
+    2175             :   {
+    2176           6 :     old_controller           = sh_control_manager_diag_.getMsg()->active_controller;
+    2177           6 :     bool controller_switched = switchControllerSrv(_midair_activation_during_controller_);
+    2178             : 
+    2179           6 :     if (!controller_switched) {
+    2180             : 
+    2181           0 :       std::stringstream ss;
+    2182           0 :       ss << "could not activate '" << _midair_activation_during_controller_ << "' for midair activation";
+    2183           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2184             : 
+    2185           0 :       return std::tuple(false, ss.str());
+    2186             :     }
+    2187             :   }
+    2188             : 
+    2189             :   // 2. turn Control Manager's output ON
+    2190             :   {
+    2191           6 :     bool output_enabled = toggleControlOutput(true);
+    2192             : 
+    2193           6 :     if (!output_enabled) {
+    2194             : 
+    2195           0 :       switchControllerSrv(old_controller);
+    2196             : 
+    2197           0 :       std::stringstream ss;
+    2198           0 :       ss << "could not enable Control Manager's output";
+    2199           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2200             : 
+    2201           0 :       return std::tuple(false, ss.str());
+    2202             :     }
+    2203             :   }
+    2204             : 
+    2205             :   // 3. activate the mid-air activation tracker
+    2206             :   // this will cause the Control Manager to output something else than min-throttle
+    2207          12 :   std::string old_tracker;
+    2208             :   {
+    2209           6 :     old_tracker = sh_control_manager_diag_.getMsg()->active_tracker;
+    2210             : 
+    2211           6 :     bool tracker_switched = switchTrackerSrv(_midair_activation_during_tracker_);
+    2212             : 
+    2213           6 :     if (!tracker_switched) {
+    2214             : 
+    2215           0 :       switchControllerSrv(old_controller);
+    2216           0 :       toggleControlOutput(false);
+    2217             : 
+    2218           0 :       std::stringstream ss;
+    2219           0 :       ss << "could not activate '" << _midair_activation_during_tracker_ << "' for midair activation";
+    2220           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2221             : 
+    2222           0 :       return std::tuple(false, ss.str());
+    2223             :     }
+    2224             :   }
+    2225             : 
+    2226             :   // 4. wait for 50 ms, that should be enough for the Pixhawk to start getting data
+    2227           6 :   ros::Duration(0.05).sleep();
+    2228             : 
+    2229             :   // 5. turn on the OFFBOARD MODE
+    2230             :   // since now, the UAV should be under our control
+    2231             :   {
+    2232           6 :     bool offboard_set = offboardSrv(true);
+    2233             : 
+    2234           6 :     if (!offboard_set) {
+    2235             : 
+    2236           0 :       switchTrackerSrv(old_tracker);
+    2237           0 :       switchControllerSrv(old_controller);
+    2238           0 :       toggleControlOutput(false);
+    2239             : 
+    2240           0 :       std::stringstream ss;
+    2241           0 :       ss << "could not activate offboard mode";
+    2242           0 :       ROS_ERROR_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2243             : 
+    2244           0 :       return std::tuple(false, ss.str());
+    2245             :     }
+    2246             :   }
+    2247             : 
+    2248             :   // remember this time, later check for timeout
+    2249           6 :   midair_activation_started_ = ros::Time::now();
+    2250             : 
+    2251             :   // start the timer which should check if the offboard is on, activate proper controller and tracker or timeout
+    2252           6 :   timer_midair_activation_.start();
+    2253             : 
+    2254           6 :   std::stringstream ss;
+    2255           6 :   ss << "midair activation initiated, starting the timer";
+    2256           6 :   ROS_INFO_STREAM_THROTTLE(1.0, "[UavManager]: " << ss.str());
+    2257             : 
+    2258           6 :   return std::tuple(true, ss.str());
+    2259             : }
+    2260             : 
+    2261             : //}
+    2262             : 
+    2263             : // | ----------------- service client wrappers ---------------- |
+    2264             : 
+    2265             : /* setOdometryCallbacksSrv() //{ */
+    2266             : 
+    2267           9 : void UavManager::setOdometryCallbacksSrv(const bool& input) {
+    2268             : 
+    2269           9 :   ROS_INFO("[UavManager]: switching odometry callbacks to %s", input ? "ON" : "OFF");
+    2270             : 
+    2271          18 :   std_srvs::SetBool srv;
+    2272             : 
+    2273           9 :   srv.request.data = input;
+    2274             : 
+    2275           9 :   bool res = sch_odometry_callbacks_.call(srv);
+    2276             : 
+    2277           9 :   if (res) {
+    2278             : 
+    2279           9 :     if (!srv.response.success) {
+    2280           0 :       ROS_WARN("[UavManager]: service call for toggle odometry callbacks returned: %s.", srv.response.message.c_str());
+    2281             :     }
+    2282             : 
+    2283             :   } else {
+    2284           0 :     ROS_ERROR("[UavManager]: service call for toggle odometry callbacks failed!");
+    2285             :   }
+    2286           9 : }
+    2287             : 
+    2288             : //}
+    2289             : 
+    2290             : /* setControlCallbacksSrv() //{ */
+    2291             : 
+    2292           1 : void UavManager::setControlCallbacksSrv(const bool& input) {
+    2293             : 
+    2294           1 :   ROS_INFO("[UavManager]: switching control callbacks to %s", input ? "ON" : "OFF");
+    2295             : 
+    2296           2 :   std_srvs::SetBool srv;
+    2297             : 
+    2298           1 :   srv.request.data = input;
+    2299             : 
+    2300           1 :   bool res = sch_control_callbacks_.call(srv);
+    2301             : 
+    2302           1 :   if (res) {
+    2303             : 
+    2304           1 :     if (!srv.response.success) {
+    2305           0 :       ROS_WARN("[UavManager]: service call for setting control callbacks returned: %s.", srv.response.message.c_str());
+    2306             :     }
+    2307             : 
+    2308             :   } else {
+    2309           0 :     ROS_ERROR("[UavManager]: service call for setting control callbacks failed!");
+    2310             :   }
+    2311           1 : }
+    2312             : 
+    2313             : //}
+    2314             : 
+    2315             : /* ungripSrv() //{ */
+    2316             : 
+    2317           0 : void UavManager::ungripSrv(void) {
+    2318             : 
+    2319           0 :   ROS_DEBUG_THROTTLE(1.0, "[UavManager]: ungripping payload");
+    2320             : 
+    2321           0 :   std_srvs::Trigger srv;
+    2322             : 
+    2323           0 :   bool res = sch_ungrip_.call(srv);
+    2324             : 
+    2325           0 :   if (res) {
+    2326             : 
+    2327           0 :     if (!srv.response.success) {
+    2328           0 :       ROS_DEBUG_THROTTLE(1.0, "[UavManager]: service call for ungripping payload returned: %s.", srv.response.message.c_str());
+    2329             :     }
+    2330             : 
+    2331             :   } else {
+    2332           0 :     ROS_DEBUG_THROTTLE(1.0, "[UavManager]: service call for ungripping payload failed!");
+    2333             :   }
+    2334           0 : }
+    2335             : 
+    2336             : //}
+    2337             : 
+    2338             : /* toggleControlOutput() //{ */
+    2339             : 
+    2340           6 : bool UavManager::toggleControlOutput(const bool& input) {
+    2341             : 
+    2342           6 :   ROS_DEBUG_THROTTLE(1.0, "[UavManager]: toggling control output %s", input ? "ON" : "OFF");
+    2343             : 
+    2344          12 :   std_srvs::SetBool srv;
+    2345             : 
+    2346           6 :   srv.request.data = input;
+    2347             : 
+    2348           6 :   bool res = sch_toggle_control_output_.call(srv);
+    2349             : 
+    2350           6 :   if (res) {
+    2351             : 
+    2352           6 :     if (!srv.response.success) {
+    2353           0 :       ROS_DEBUG_THROTTLE(1.0, "[UavManager]: service call for control output returned: %s.", srv.response.message.c_str());
+    2354           0 :       return false;
+    2355             :     } else {
+    2356           6 :       return true;
+    2357             :     }
+    2358             : 
+    2359             :   } else {
+    2360           0 :     ROS_DEBUG_THROTTLE(1.0, "[UavManager]: service call for control output failed!");
+    2361           0 :     return false;
+    2362             :   }
+    2363             : }
+    2364             : 
+    2365             : //}
+    2366             : 
+    2367             : /* offboardSrv() //{ */
+    2368             : 
+    2369           6 : bool UavManager::offboardSrv(const bool in) {
+    2370             : 
+    2371           6 :   ROS_DEBUG_THROTTLE(1.0, "[UavManager]: setting offboard to %d", in);
+    2372             : 
+    2373          12 :   std_srvs::Trigger srv;
+    2374             : 
+    2375           6 :   bool res = sch_offboard_.call(srv);
+    2376             : 
+    2377           6 :   if (!res) {
+    2378             : 
+    2379           0 :     ROS_DEBUG_THROTTLE(1.0, "[UavManager]: service call for offboard failed!");
+    2380           0 :     return false;
+    2381             : 
+    2382             :   } else {
+    2383             : 
+    2384           6 :     if (!srv.response.success) {
+    2385           0 :       ROS_DEBUG_THROTTLE(1.0, "[UavManager]: service call for offboard failed, returned: %s", srv.response.message.c_str());
+    2386           0 :       return false;
+    2387             :     } else {
+    2388           6 :       return true;
+    2389             :     }
+    2390             :   }
+    2391             : }
+    2392             : 
+    2393             : //}
+    2394             : 
+    2395             : /* pirouetteSrv() //{ */
+    2396             : 
+    2397           0 : void UavManager::pirouetteSrv(void) {
+    2398             : 
+    2399           0 :   std_srvs::Trigger srv;
+    2400             : 
+    2401           0 :   bool res = sch_pirouette_.call(srv);
+    2402             : 
+    2403           0 :   if (res) {
+    2404             : 
+    2405           0 :     if (!srv.response.success) {
+    2406           0 :       ROS_WARN_THROTTLE(1.0, "[UavManager]: service call for pirouette returned: %s.", srv.response.message.c_str());
+    2407             :     }
+    2408             : 
+    2409             :   } else {
+    2410           0 :     ROS_ERROR_THROTTLE(1.0, "[UavManager]: service call for pirouette failed!");
+    2411             :   }
+    2412           0 : }
+    2413             : 
+    2414             : //}
+    2415             : 
+    2416             : /* disarmSrv() //{ */
+    2417             : 
+    2418           1 : void UavManager::disarmSrv(void) {
+    2419             : 
+    2420           2 :   std_srvs::SetBool srv;
+    2421             : 
+    2422           1 :   srv.request.data = false;
+    2423             : 
+    2424           1 :   bool res = sch_arm_.call(srv);
+    2425             : 
+    2426           1 :   if (res) {
+    2427             : 
+    2428           1 :     if (!srv.response.success) {
+    2429           0 :       ROS_WARN_THROTTLE(1.0, "[UavManager]: service call disarming returned: %s.", srv.response.message.c_str());
+    2430             :     }
+    2431             : 
+    2432             :   } else {
+    2433           0 :     ROS_ERROR_THROTTLE(1.0, "[UavManager]: service call for disarming failed!");
+    2434             :   }
+    2435           1 : }
+    2436             : 
+    2437             : //}
+    2438             : 
+    2439             : /* switchControllerSrv() //{ */
+    2440             : 
+    2441          15 : bool UavManager::switchControllerSrv(const std::string& controller) {
+    2442             : 
+    2443          15 :   ROS_INFO_STREAM("[UavManager]: activating controller '" << controller << "'");
+    2444             : 
+    2445          30 :   mrs_msgs::String srv;
+    2446          15 :   srv.request.value = controller;
+    2447             : 
+    2448          15 :   bool res = sch_switch_controller_.call(srv);
+    2449             : 
+    2450          15 :   if (res) {
+    2451             : 
+    2452          15 :     if (!srv.response.success) {
+    2453           0 :       ROS_WARN("[UavManager]: service call for switching controller returned: '%s'", srv.response.message.c_str());
+    2454             :     }
+    2455             : 
+    2456          15 :     return srv.response.success;
+    2457             : 
+    2458             :   } else {
+    2459             : 
+    2460           0 :     ROS_ERROR("[UavManager]: service call for switching controller failed!");
+    2461             : 
+    2462           0 :     return false;
+    2463             :   }
+    2464             : }
+    2465             : 
+    2466             : //}
+    2467             : 
+    2468             : /* switchTrackerSrv() //{ */
+    2469             : 
+    2470          16 : bool UavManager::switchTrackerSrv(const std::string& tracker) {
+    2471             : 
+    2472          16 :   ROS_INFO_STREAM("[UavManager]: activating tracker '" << tracker << "'");
+    2473             : 
+    2474             : 
+    2475          32 :   mrs_msgs::String srv;
+    2476          16 :   srv.request.value = tracker;
+    2477             : 
+    2478          16 :   bool res = sch_switch_tracker_.call(srv);
+    2479             : 
+    2480          16 :   if (res) {
+    2481             : 
+    2482          16 :     if (!srv.response.success) {
+    2483           0 :       ROS_WARN("[UavManager]: service call for switching tracker returned: '%s'", srv.response.message.c_str());
+    2484             :     }
+    2485             : 
+    2486          16 :     return srv.response.success;
+    2487             : 
+    2488             :   } else {
+    2489             : 
+    2490           0 :     ROS_ERROR("[UavManager]: service call for switching tracker failed!");
+    2491             : 
+    2492           0 :     return false;
+    2493             :   }
+    2494             : }
+    2495             : 
+    2496             : //}
+    2497             : 
+    2498             : /* landSrv() //{ */
+    2499             : 
+    2500           1 : bool UavManager::landSrv(void) {
+    2501             : 
+    2502           1 :   ROS_INFO("[UavManager]: calling for landing");
+    2503             : 
+    2504           2 :   std_srvs::Trigger srv;
+    2505             : 
+    2506           1 :   bool res = sch_land_.call(srv);
+    2507             : 
+    2508           1 :   if (res) {
+    2509             : 
+    2510           1 :     if (!srv.response.success) {
+    2511           0 :       ROS_WARN("[UavManager]: service call for landing returned: '%s'", srv.response.message.c_str());
+    2512             :     }
+    2513             : 
+    2514           1 :     return srv.response.success;
+    2515             : 
+    2516             :   } else {
+    2517             : 
+    2518           0 :     ROS_ERROR("[UavManager]: service call for landing failed!");
+    2519             : 
+    2520           0 :     return false;
+    2521             :   }
+    2522             : }
+    2523             : 
+    2524             : //}
+    2525             : 
+    2526             : /* elandSrv() //{ */
+    2527             : 
+    2528           0 : bool UavManager::elandSrv(void) {
+    2529             : 
+    2530           0 :   ROS_INFO("[UavManager]: calling for eland");
+    2531             : 
+    2532           0 :   std_srvs::Trigger srv;
+    2533             : 
+    2534           0 :   bool res = sch_eland_.call(srv);
+    2535             : 
+    2536           0 :   if (res) {
+    2537             : 
+    2538           0 :     if (!srv.response.success) {
+    2539           0 :       ROS_WARN("[UavManager]: service call for eland returned: '%s'", srv.response.message.c_str());
+    2540             :     }
+    2541             : 
+    2542           0 :     return srv.response.success;
+    2543             : 
+    2544             :   } else {
+    2545             : 
+    2546           0 :     ROS_ERROR("[UavManager]: service call for eland failed!");
+    2547             : 
+    2548           0 :     return false;
+    2549             :   }
+    2550             : }
+    2551             : 
+    2552             : //}
+    2553             : 
+    2554             : /* ehoverSrv() //{ */
+    2555             : 
+    2556           0 : bool UavManager::ehoverSrv(void) {
+    2557             : 
+    2558           0 :   ROS_INFO("[UavManager]: calling for ehover");
+    2559             : 
+    2560           0 :   std_srvs::Trigger srv;
+    2561             : 
+    2562           0 :   bool res = sch_ehover_.call(srv);
+    2563             : 
+    2564           0 :   if (res) {
+    2565             : 
+    2566           0 :     if (!srv.response.success) {
+    2567           0 :       ROS_WARN("[UavManager]: service call for ehover returned: '%s'", srv.response.message.c_str());
+    2568             :     }
+    2569             : 
+    2570           0 :     return srv.response.success;
+    2571             : 
+    2572             :   } else {
+    2573             : 
+    2574           0 :     ROS_ERROR("[UavManager]: service call for ehover failed!");
+    2575             : 
+    2576           0 :     return false;
+    2577             :   }
+    2578             : }
+    2579             : 
+    2580             : //}
+    2581             : 
+    2582             : /* takeoffSrv() //{ */
+    2583             : 
+    2584           1 : bool UavManager::takeoffSrv(void) {
+    2585             : 
+    2586           1 :   ROS_INFO("[UavManager]: calling for takeoff to height '%.2f m'", _takeoff_height_);
+    2587             : 
+    2588           2 :   mrs_msgs::Vec1 srv;
+    2589             : 
+    2590           1 :   srv.request.goal = _takeoff_height_;
+    2591             : 
+    2592           1 :   bool res = sch_takeoff_.call(srv);
+    2593             : 
+    2594           1 :   if (res) {
+    2595             : 
+    2596           1 :     if (!srv.response.success) {
+    2597           0 :       ROS_WARN("[UavManager]: service call for takeoff returned: '%s'", srv.response.message.c_str());
+    2598             :     }
+    2599             : 
+    2600           1 :     return srv.response.success;
+    2601             : 
+    2602             :   } else {
+    2603             : 
+    2604           0 :     ROS_ERROR("[UavManager]: service call for takeoff failed!");
+    2605             : 
+    2606           0 :     return false;
+    2607             :   }
+    2608             : }
+    2609             : 
+    2610             : //}
+    2611             : 
+    2612             : /* emergencyReferenceSrv() //{ */
+    2613             : 
+    2614           0 : bool UavManager::emergencyReferenceSrv(const mrs_msgs::ReferenceStamped& goal) {
+    2615             : 
+    2616           0 :   ROS_INFO_THROTTLE(1.0, "[UavManager]: calling for emergency reference");
+    2617             : 
+    2618           0 :   mrs_msgs::ReferenceStampedSrv srv;
+    2619             : 
+    2620           0 :   srv.request.header    = goal.header;
+    2621           0 :   srv.request.reference = goal.reference;
+    2622             : 
+    2623           0 :   bool res = sch_emergency_reference_.call(srv);
+    2624             : 
+    2625           0 :   if (res) {
+    2626             : 
+    2627           0 :     if (!srv.response.success) {
+    2628           0 :       ROS_WARN_THROTTLE(1.0, "[UavManager]: service call for emergency reference returned: '%s'", srv.response.message.c_str());
+    2629             :     }
+    2630             : 
+    2631           0 :     return srv.response.success;
+    2632             : 
+    2633             :   } else {
+    2634             : 
+    2635           0 :     ROS_ERROR_THROTTLE(1.0, "[UavManager]: service call for emergency reference failed!");
+    2636             : 
+    2637           0 :     return false;
+    2638             :   }
+    2639             : }
+    2640             : 
+    2641             : //}
+    2642             : 
+    2643             : }  // namespace uav_manager
+    2644             : 
+    2645             : }  // namespace mrs_uav_managers
+    2646             : 
+    2647             : #include <pluginlib/class_list_macros.h>
+    2648           7 : PLUGINLIB_EXPORT_CLASS(mrs_uav_managers::uav_manager::UavManager, nodelet::Nodelet)
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/ruby.png b/ruby.png new file mode 100644 index 0000000000..991b6d4ec9 Binary files /dev/null and b/ruby.png differ diff --git a/snow.png b/snow.png new file mode 100644 index 0000000000..2cdae107fc Binary files /dev/null and b/snow.png differ diff --git a/updown.png b/updown.png new file mode 100644 index 0000000000..aa56a238b3 Binary files /dev/null and b/updown.png differ