Skip to content

feat(opennav_docking): add on-demand detector client & unit tests for dock plugins (#5015) #5218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

bkoensgen
Copy link

@bkoensgen bkoensgen commented Jun 2, 2025

  • Add detector client initialization in SimpleNonChargingDock
  • Mirror the same logic in SimpleChargingDock
  • Expand unit-test coverage for both dock plugins

Basic Info

Info Value
Ticket(s) this addresses #5015
Primary OS tested on Official Nav2 Rolling Docker image
Robotic platform tested on Unit tests only (colcon test)
Does this PR contain AI-generated software? No

Description of contribution in a few bullet points

  • Introduce on-demand external-detector control for both charging and non-charging dock plugins
    • New parameters: detector_service_name, detector_service_timeout, subscribe_toggle
    • Detector started/stopped via std_srvs/Trigger only when first needed
  • SimpleNonChargingDock now creates the detector client (symmetry with charging dock)
  • Unit tests added to validate service call logic and TF handling

Description of documentation updates required

  • Added the three new parameters to nav2_docking/README.md

Description of how this change was tested

  • colcon test --packages-select opennav_dockingall tests pass
  • Manual sanity check: plugins load without warnings inside the Rolling dev-container

For Maintainers

  • Check that any new parameters added are updated in docs.nav2.org
  • Check that any significant change is added to the migration guide
  • Check that any new features OR changes to existing behaviors are reflected in the tuning guide
  • Check that any new functions have Doxygen added
  • Check that any new features have test coverage
  • Check that any new plugins are added to the plugins page
  • If BT Node, additionally: add to BT's XML index of nodes for Groot, BT package's readme table, and BT library lists

Copy link
Contributor

mergify bot commented Jun 2, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from f580de2 to feb37e8 Compare June 2, 2025 14:56
@SteveMacenski SteveMacenski linked an issue Jun 2, 2025 that may be closed by this pull request
Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good first stab! I have some questions and suggestions, but largely its a good starting point for a couple of hopefully quick iterations. The changes requested in this plugin are the same in both, but I only reviewed the one just to avoid duplicating every comment. Take each comment for both plugin files

@@ -133,11 +154,6 @@ void SimpleChargingDock::configure(

if (use_external_detection_pose_) {
dock_pose_.header.stamp = rclcpp::Time(0);
dock_pose_sub_ = node_->create_subscription<geometry_msgs::msg::PoseStamped>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If !subscribe_toggle_, I think we should create this, no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the code should move back up here. You also don't need to check !detected_pose_sub_

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkoensgen this was not completed :-)

Copy link

codecov bot commented Jun 2, 2025

Codecov Report

Attention: Patch coverage is 87.93103% with 14 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...cking/opennav_docking/src/simple_charging_dock.cpp 88.00% 6 Missing ⚠️
...g/opennav_docking/src/simple_non_charging_dock.cpp 88.00% 6 Missing ⚠️
...av2_docking/opennav_docking/src/docking_server.cpp 81.81% 2 Missing ⚠️
Files with missing lines Coverage Δ
...g/include/opennav_docking/simple_charging_dock.hpp 100.00% <100.00%> (ø)
...clude/opennav_docking/simple_non_charging_dock.hpp 100.00% <100.00%> (ø)
nav2_docking/opennav_docking/src/dock_database.cpp 98.76% <100.00%> (+0.01%) ⬆️
...ore/include/opennav_docking_core/charging_dock.hpp 80.00% <ø> (ø)
...include/opennav_docking_core/non_charging_dock.hpp 87.50% <ø> (ø)
...av2_docking/opennav_docking/src/docking_server.cpp 90.50% <81.81%> (+0.41%) ⬆️
...cking/opennav_docking/src/simple_charging_dock.cpp 94.81% <88.00%> (-3.39%) ⬇️
...g/opennav_docking/src/simple_non_charging_dock.cpp 94.35% <88.00%> (-3.63%) ⬇️

... and 8 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

mergify bot commented Jun 4, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen marked this pull request as draft June 4, 2025 21:10
@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 95ed998 to dcb62d4 Compare June 4, 2025 21:15
Copy link
Contributor

mergify bot commented Jun 4, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@SteveMacenski
Copy link
Member

@bkoensgen re-request a review from me in the github UX when you're ready for me to take a look again (and CI is building 😉 )

Copy link
Contributor

mergify bot commented Jun 4, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

3 similar comments
Copy link
Contributor

mergify bot commented Jun 4, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

Copy link
Contributor

mergify bot commented Jun 4, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

Copy link
Contributor

mergify bot commented Jun 4, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from b6ee1e3 to e000987 Compare June 4, 2025 23:27
Copy link
Contributor

mergify bot commented Jun 4, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

1 similar comment
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 118fe82 to 804520a Compare June 5, 2025 13:54
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 694feb0 to 7153b31 Compare June 5, 2025 14:02
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 49cd52b to 76b096b Compare June 5, 2025 14:15
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 8b7d652 to b3f4910 Compare June 5, 2025 14:54
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

1 similar comment
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from cbf5362 to e21641e Compare June 5, 2025 15:34
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 43d42bc to 4e7de42 Compare June 5, 2025 15:52
Copy link
Contributor

mergify bot commented Jun 5, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from ccd84ce to 4b0b1da Compare June 13, 2025 14:46
Copy link
Contributor

mergify bot commented Jun 13, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch 2 times, most recently from 9750cac to 5bd06d3 Compare June 15, 2025 17:00
Copy link
Contributor

mergify bot commented Jun 15, 2025

@bkoensgen, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch 7 times, most recently from dc2325d to 7c5c042 Compare June 16, 2025 10:44
@bkoensgen
Copy link
Author

@SteveMacenski

Thanks for the detailed review and guidance! I've pushed up the changes addressing your feedback.

The biggest change is that I've moved the detector lifecycle management (start/stopDetectionProcess) into the plugin API itself. The DockingServer now just calls these methods, which gives individual plugins full control over how and when they manage their perception resources (like starting/stopping a GPU-intensive node). This felt a lot cleaner and more robust.

Here’s a quick rundown of the other changes:

  • Service Client & Dependencies: Switched over to nav2_util::ServiceClient as you suggested and cleaned up the CMakeLists to properly link std_srvs.
  • Test Coverage: Beefed up the unit tests for both SimpleChargingDock and SimpleNonChargingDock. They now cover the new subscribe_toggle logic and the service failure edge cases we discussed.
  • Test Reliability: That also gave me a chance to fix a race condition in the Python smoke tests related to TF propagation. They should be much more stable in CI now.
  • Git History: Squashed everything down to a single commit for a clean merge.

Should be in good shape for another look now. Let me know what you think!

@bkoensgen bkoensgen requested a review from SteveMacenski June 16, 2025 11:44
Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good job on the tests, thanks for that! Beyond these changes which are mostly superficial, we need to also have the migration guide and configuration guide for docking server updated for these new parameters and capabilities. Please open a PR to include these & I think this is largely ready to go! :-)

All comments I made in the simple charging dock also apply to the implementation of the non-charging plugin too

detected_pose_sub_ = node_->create_subscription<geometry_msgs::msg::PoseStamped>(
"detected_dock_pose", rclcpp::SensorDataQoS(),
[this](const geometry_msgs::msg::PoseStamped::SharedPtr pose) {
detected_dock_pose_ = *pose;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should uses of detected_dock_pose_ make sure that detector_state_ is on? Throw otherwise

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not completed either

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. I checked getRefinedPose and it already has a guard clause at the top (if (!detector_enabled_)) that prevents detected_dock_pose_ from being used improperly.

Returning false there seems like the right behavior for the control loop, so I think we're all set on this one.

"detected_dock_pose", rclcpp::SensorDataQoS(),
[this](const geometry_msgs::msg::PoseStamped::SharedPtr pose) {
detected_dock_pose_ = *pose;
detector_state_ = DetectorState::ON;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove. This is always set anyway on L384 below when we exist the function. It has no impact in the callback (ditto for the subscriber above).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not completed either

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I did remove this initially based on your feedback! But it turned out to cause a subtle race condition that made the tests fail.

What happened was that startDetection() would set the detector to "enabled" immediately, but getRefinedPose() would then be called before the first message from the topic actually arrived. This caused the timestamp check to fail.

The only way I found to make it robustly pass the tests was to put the state update back here, inside the callback. This guarantees the plugin only considers itself 'active' once it has actually received data.

It's a bit counter-intuitive, but it seems necessary to handle that timing issue. Let me know if you have other ideas on how to tackle this!

This change introduces an API to dynamically enable and disable external
docking detectors, such as those based on AI, to conserve system
resources when not actively docking.

Key changes:
- Added `startDetectionProcess()` and `stopDetectionProcess()` to the
  docking plugin interface (`ChargingDock` and `NonChargingDock`).
- Implemented this logic in `SimpleChargingDock` and
  `SimpleNonChargingDock` using a `std_srvs/Trigger` service call and
  dynamic topic subscription to manage the detector's lifecycle.
- The `DockingServer` now ensures `stopDetectionProcess()` is called
  on all exit paths, including success, failure, and cancellation,
  to prevent dangling resources.
- Added new parameters (`detector_service_name`, `subscribe_toggle`, etc.)
  to configure this behavior and updated the README documentation.
- Added comprehensive C++ unit tests to verify the new detector
  lifecycle logic, specifically covering service failure cases and
  proper cleanup on action termination.

Closes ros-navigation#5015
Signed-off-by: Koensgen Benjamin <b.koensgen@gmail.com>

-

updtae

Signed-off-by: Koensgen Benjamin <b.koensgen@gmail.com>
@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 896fa48 to d88d2df Compare June 17, 2025 14:25
@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 15caec9 to 2e6dc99 Compare June 17, 2025 19:14
@SteveMacenski
Copy link
Member

Mark this as ready to review again once you'd like me to take a look!

@bkoensgen bkoensgen requested a review from SteveMacenski June 17, 2025 20:18
// Detector control parameters
std::string detector_service_name_;
double detector_service_timeout_{5.0};
bool subscribe_toggle_{true};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool subscribe_toggle_{true};
bool subscribe_toggle_{false};

// Detector control parameters
std::string detector_service_name_;
double detector_service_timeout_{5.0};
bool subscribe_toggle_{true};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool subscribe_toggle_{true};
bool subscribe_toggle_{false};

@@ -133,11 +154,6 @@ void SimpleChargingDock::configure(

if (use_external_detection_pose_) {
dock_pose_.header.stamp = rclcpp::Time(0);
dock_pose_sub_ = node_->create_subscription<geometry_msgs::msg::PoseStamped>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkoensgen this was not completed :-)

/**
* @brief Start external detection process (service call + subscribe).
*/
void startDetectionProcess() override {startDetection();}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkoensgen this was not completed :-)

rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr detected_pose_sub_;

// Simple finite-state machine for detector status
enum class DetectorState { OFF, ON };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkoensgen this was not completed :-)

@@ -133,11 +155,6 @@ void SimpleChargingDock::configure(

if (use_external_detection_pose_) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not completed either


void SimpleChargingDock::deactivate()
{
RCLCPP_DEBUG(node_->get_logger(), "SimpleChargingDock deactivated");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not completed either


void SimpleChargingDock::activate()
{
RCLCPP_DEBUG(node_->get_logger(), "SimpleChargingDock activated");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not completed either

detected_pose_sub_ = node_->create_subscription<geometry_msgs::msg::PoseStamped>(
"detected_dock_pose", rclcpp::SensorDataQoS(),
[this](const geometry_msgs::msg::PoseStamped::SharedPtr pose) {
detected_dock_pose_ = *pose;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not completed either

"detected_dock_pose", rclcpp::SensorDataQoS(),
[this](const geometry_msgs::msg::PoseStamped::SharedPtr pose) {
detected_dock_pose_ = *pose;
detector_state_ = DetectorState::ON;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not completed either

@SteveMacenski
Copy link
Member

@bkoensgen the majority of my review comments were not completed, please see above

Signed-off-by: Koensgen Benjamin <b.koensgen@gmail.com>

fix(docking): Change subscribe_toggle default to false

Signed-off-by: Koensgen Benjamin <b.koensgen@gmail.com>

-
@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 2e6dc99 to 2f12cf1 Compare June 17, 2025 20:50
This commit addresses several code review suggestions to improve the design and robustness of the docking plugins.

- Replaced the `DetectorState` enum with a simpler `bool detector_enabled_` for clarity.
- Encapsulated the detection process lifecycle within the plugin itself. The `deactivate` method now ensures `stopDetectionProcess` is called, improving encapsulation and simplifying the `DockDatabase`.
- Refactored the `configure` method in plugins to group related logic, improving readability.
- Cleaned up redundant checks and calls in both the plugins and the `DockingServer` for more robust and intentional code.

Signed-off-by: Koensgen Benjamin <b.koensgen@gmail.com>
@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 74b8455 to fc7ae9f Compare June 18, 2025 14:05
…back

The previous refactoring introduced a race condition where the detector
was marked as 'enabled' in startDetection() before a message was
actually received.

This caused tests to fail because getRefinedPose() would be called
with an enabled state but no valid/recent data.

This commit fixes the issue by moving the `detector_enabled_ = true`
assignment into the subscription callback. This ensures the plugin's
state accurately reflects that it has received at least one valid
data point before being considered active.

Signed-off-by: Koensgen Benjamin <b.koensgen@gmail.com>
@bkoensgen bkoensgen force-pushed the feature/detector-toggle-5015 branch from 3fb99d3 to 96bdb23 Compare June 18, 2025 15:16
@bkoensgen bkoensgen requested a review from SteveMacenski June 18, 2025 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Docking] Create API to enable / disable detector
2 participants