Skip to content

Commit 9cf97b5

Browse files
committed
Adding non-charging dock support to docking server (for conveyers, pallots, etc) (#4627)
* adding non-charging dock support to docking server Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> * docs and linting * adding unit tests Signed-off-by: Steve Macenski <stevenmacenski@gmail.com> --------- Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
1 parent 3e3506f commit 9cf97b5

File tree

14 files changed

+840
-27
lines changed

14 files changed

+840
-27
lines changed

nav2_docking/README.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Open Navigation's Nav2 Docking Framework
22

3-
This package contains an automatic robot docking framework & auxiliary tools. It uses plugin `dock` implementations for a particular platform to enable the framework to generalize to robots of many different kinematic models, charging methods, sensor modalities, and so on. It can also handle a database of many different docking locations and dock models to handle a heterogeneous environment. This task server is designed be called by an application BT or autonomy application to dock once completed with tasks or battery is low -- _not_ within the navigate-to-pose action itself (though `undock` may be called from inside navigate actions!).
3+
This package contains an automatic robot docking framework & auxiliary tools. It uses plugin `dock` implementations for a particular platform to enable the framework to generalize to robots of many different kinematic models, charging methods, sensor modalities, non-charging dock request needs, and so on. It can also handle a database of many different docking locations and dock models to handle a heterogeneous environment. This task server is designed be called by an application BT or autonomy application to dock once completed with tasks or battery is low -- _not_ within the navigate-to-pose action itself (though `undock` may be called from inside navigate actions!).
44

55
This work is sponsored by [NVIDIA](https://www.nvidia.com/en-us/) and created by [Open Navigation LLC](https://opennav.org).
66

@@ -24,17 +24,17 @@ The Docking Framework has 5 main components:
2424
- `Navigator`: A NavigateToPose action client to navigate the robot to the dock's staging pose if not with the prestaging tolerances
2525
- `DockDatabase`: A database of dock instances in an environment and their associated interfaces for transacting with each type. An arbitrary number of types are supported.
2626
- `Controller`: A spiral-based graceful controller to use for the vision-control loop for docking
27-
- `ChargingDock`: Plugins that describe the dock and how to transact with it (check if charging, detection, etc). You can find this plugin header in the `opennav_docking_core` package.
27+
- `ChargingDock` and `NonChargingDock`: Plugins that describe the dock and how to transact with it (check if charging, detection, etc). You can find these plugin headers in the `opennav_docking_core` package.
2828

29-
The `ChargingDock` plugins are the heart of the customizability of the framework to support any type of charging dock for any kind of robot. The `DockDatabase` is how you describe where these docks exist in your environment to interact with and any of them may be used in your docking request.
29+
The `ChargingDock` and `NonChargingDock` plugins are the heart of the customizability of the framework to support any type of charging or non-charging dock for any kind of robot. This means you can both dock with charging stations, as well as non-charging infrastructure such as static locations (ex. conveyers) or dynamic locations (ex. pallets). The `DockDatabase` is how you describe where these docks exist in your environment to interact with and any of them may be used in your docking request. For dynamic locations like docking with movable objects, the action request can include an approximate docking location that uses vision-control loops to refine motion into it.
3030

3131
The docking procedure is as follows:
3232
1. Take action request and obtain the dock's plugin and its pose
3333
2. If the robot is not within the prestaging tolerance of the dock's staging pose, navigate to the staging pose
3434
3. Use the dock's plugin to initially detect the dock and return the docking pose
3535
4. Enter a vision-control loop where the robot attempts to reach the docking pose while its actively being refined by the vision system
3636
5. Exit the vision-control loop once contact has been detected or charging has started
37-
6. Wait until charging starts and return success.
37+
6. Wait until charging starts (if applicable) and return success.
3838

3939
If anywhere this procedure is unsuccessful, `N` retries may be made by driving back to the dock's staging pose and trying again. If still unsuccessful, it will return a failure code to indicate what kind of failure occurred to the client.
4040

@@ -74,7 +74,7 @@ This service exists to potentially reload the dock server's known dock database
7474

7575
There are two unique elements to consider in specifying docks: dock _instances_ and dock _plugins_. Dock instances are instances of a particular dock in the map, as the database may contain many known docks (and you can specify which by name you'd like to dock at). Dock plugins are the model of dock that each is an instance of. The plugins contain the capabilities to generically detect and connect to a particular dock model. This separation allows us to efficiently enable many individual docking locations of potentially several different revisions with different attributes.
7676

77-
The **dock plugins** are specified in the parameter file as shown below. If you're familiar with plugins in other Nav2 servers, this should look like a familiar design pattern. Note that there is no specific information about the dock's pose or instances. These are generic attributes about the dock revision (such as staging pose, enable charging command, detection method, etc). You can add additional parameters in the dock's namespace as you choose (for example `timeout`).
77+
The **dock plugins** are specified in the parameter file as shown below. If you're familiar with plugins in other Nav2 servers, this should look like a familiar design pattern. Note that there is no specific information about the dock's pose or instances. These are generic attributes about the dock revision (such as staging pose, enable charging command, detection method, etc). You can add additional parameters in the dock's namespace as you choose (for example `timeout`). These can be of both charging and non-charging types.
7878

7979
```
8080
dock_plugins: ["dockv1", "dockv3"]
@@ -145,23 +145,26 @@ There are two functions used during dock approach:
145145
* `isCharging`: The approach stops when the robot reports `isDocked`, then we wait
146146
for charging to start by calling `isCharging`.
147147
* This may be implemented using the `sensor_msgs/BatteryState` message to check the power status or for charging current.
148+
* Used for charging-typed plugins.
148149

149150
Similarly, there are two functions used during undocking:
150151

151152
* `disableCharging`: This function is called before undocking commences to help
152153
prevent wear on the charge contacts. If the charge dock supports turning off
153154
the charge current, it should be done here.
155+
* Used for charging-typed plugins.
154156
* `hasStoppedCharging`: This function is called while the controller is undocking.
155157
Undocking is successful when charging has stopped and the robot has returned to
156158
the staging pose.
159+
* Used for charging-typed plugins.
157160

158161
Keep in mind that the docking and undocking functions should return quickly as they
159162
will be called inside the control loop. Also make sure that `isDocked` should
160163
return true if `isCharging` returns true.
161164

162-
### Simple Charging Dock Plugin
165+
### Simple (Non-) Charging Dock Plugins
163166

164-
The `SimpleChargingDock` plugin is an example with many common options which may be fully functional for
167+
The `SimpleChargingDock` and `SimpleNonChargingDock` plugins are examples with many common options which may be fully functional for
165168
some robots.
166169

167170
`getStagingPose` applys a parameterized translational and rotational offset to the dock pose to obtain the staging pose.
@@ -174,7 +177,7 @@ During the docking approach, there are two options for detecting `isDocked`:
174177
1. We can check the joint states of the wheels if the current has spiked above a set threshold to indicate that the robot has made contact with the dock or other physical object.
175178
2. The dock pose is compared with the robot pose and `isDocked` returns true when the distance drops below the specified `docking_threshold`.
176179

177-
The `isCharging` and `hasStoppedCharging` functions have two options:
180+
The `isCharging` and `hasStoppedCharging` functions have two options, when using the charging dock type:
178181
1. Subscribing to a `sensor_msgs/BatteryState` message on topic `battery_state`. The robot is considered charging when the `current` field of the message exceeds the `charging_threshold`.
179182
2. We can return that we are charging is `isDocked() = true`, which is useful for initial testing or low-reliability docking until battery state or similar information is available.
180183

nav2_docking/opennav_docking/CMakeLists.txt

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,34 @@ ament_target_dependencies(simple_charging_dock
107107
)
108108
target_link_libraries(simple_charging_dock pose_filter)
109109

110+
add_library(simple_non_charging_dock SHARED
111+
src/simple_non_charging_dock.cpp
112+
)
113+
target_include_directories(simple_non_charging_dock
114+
PUBLIC
115+
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
116+
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
117+
)
118+
target_link_libraries(simple_non_charging_dock PUBLIC
119+
${geometry_msgs_TARGETS}
120+
opennav_docking_core::opennav_docking_core
121+
pose_filter
122+
rclcpp::rclcpp
123+
rclcpp_lifecycle::rclcpp_lifecycle
124+
${sensor_msgs_TARGETS}
125+
tf2_geometry_msgs::tf2_geometry_msgs
126+
tf2_ros::tf2_ros
127+
)
128+
target_link_libraries(simple_non_charging_dock PRIVATE
129+
nav2_util::nav2_util_core
130+
pluginlib::pluginlib
131+
tf2::tf2
132+
)
133+
110134
pluginlib_export_plugin_description_file(opennav_docking_core plugins.xml)
111135

112-
install(TARGETS ${library_name} controller pose_filter simple_charging_dock
136+
install(TARGETS ${library_name} controller pose_filter simple_charging_dock simple_non_charging_dock
137+
EXPORT ${PROJECT_NAME}
113138
ARCHIVE DESTINATION lib
114139
LIBRARY DESTINATION lib
115140
RUNTIME DESTINATION bin

nav2_docking/opennav_docking/include/opennav_docking/simple_charging_dock.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class SimpleChargingDock : public opennav_docking_core::ChargingDock
142142
double charging_threshold_;
143143
// If not using an external pose reference, this is the distance threshold
144144
double docking_threshold_;
145+
std::string base_frame_id_;
145146
// Offset for staging pose relative to dock pose
146147
double staging_x_offset_;
147148
double staging_yaw_offset_;
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright (c) 2024 Open Navigation LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef OPENNAV_DOCKING__SIMPLE_NON_CHARGING_DOCK_HPP_
16+
#define OPENNAV_DOCKING__SIMPLE_NON_CHARGING_DOCK_HPP_
17+
18+
#include <string>
19+
#include <memory>
20+
#include <vector>
21+
22+
#include "geometry_msgs/msg/pose_stamped.hpp"
23+
#include "sensor_msgs/msg/battery_state.hpp"
24+
#include "sensor_msgs/msg/joint_state.hpp"
25+
#include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
26+
#include "tf2/utils.h"
27+
28+
#include "opennav_docking_core/non_charging_dock.hpp"
29+
#include "opennav_docking/pose_filter.hpp"
30+
31+
namespace opennav_docking
32+
{
33+
34+
class SimpleNonChargingDock : public opennav_docking_core::NonChargingDock
35+
{
36+
public:
37+
/**
38+
* @brief Constructor
39+
*/
40+
SimpleNonChargingDock()
41+
: NonChargingDock()
42+
{}
43+
44+
/**
45+
* @param parent pointer to user's node
46+
* @param name The name of this planner
47+
* @param tf A pointer to a TF buffer
48+
*/
49+
virtual void configure(
50+
const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
51+
const std::string & name, std::shared_ptr<tf2_ros::Buffer> tf);
52+
53+
/**
54+
* @brief Method to cleanup resources used on shutdown.
55+
*/
56+
virtual void cleanup() {}
57+
58+
/**
59+
* @brief Method to active Behavior and any threads involved in execution.
60+
*/
61+
virtual void activate() {}
62+
63+
/**
64+
* @brief Method to deactive Behavior and any threads involved in execution.
65+
*/
66+
virtual void deactivate() {}
67+
68+
/**
69+
* @brief Method to obtain the dock's staging pose. This method should likely
70+
* be using TF and the dock's pose information to find the staging pose from
71+
* a static or parameterized staging pose relative to the docking pose
72+
* @param pose Dock with pose
73+
* @param frame Dock's frame of pose
74+
* @return PoseStamped of staging pose in the specified frame
75+
*/
76+
virtual geometry_msgs::msg::PoseStamped getStagingPose(
77+
const geometry_msgs::msg::Pose & pose, const std::string & frame);
78+
79+
/**
80+
* @brief Method to obtain the refined pose of the dock, usually based on sensors
81+
* @param pose The initial estimate of the dock pose.
82+
* @param frame The frame of the initial estimate.
83+
*/
84+
virtual bool getRefinedPose(geometry_msgs::msg::PoseStamped & pose, std::string id);
85+
86+
/**
87+
* @copydoc opennav_docking_core::ChargingDock::isDocked
88+
*/
89+
virtual bool isDocked();
90+
91+
protected:
92+
void jointStateCallback(const sensor_msgs::msg::JointState::SharedPtr state);
93+
94+
// Optionally subscribe to a detected dock pose topic
95+
rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr dock_pose_sub_;
96+
rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr dock_pose_pub_;
97+
rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr filtered_dock_pose_pub_;
98+
rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr staging_pose_pub_;
99+
// If subscribed to a detected pose topic, will contain latest message
100+
geometry_msgs::msg::PoseStamped detected_dock_pose_;
101+
// This is the actual dock pose once it has the specified translation/rotation applied
102+
// If not subscribed to a topic, this is simply the database dock pose
103+
geometry_msgs::msg::PoseStamped dock_pose_;
104+
105+
// Optionally subscribe to joint state message, used to determine if stalled
106+
rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr joint_state_sub_;
107+
std::vector<std::string> stall_joint_names_;
108+
double stall_velocity_threshold_, stall_effort_threshold_;
109+
bool is_stalled_;
110+
111+
// An external reference (such as image_proc::TrackMarkerNode) can be used to detect dock
112+
bool use_external_detection_pose_;
113+
double external_detection_timeout_;
114+
tf2::Quaternion external_detection_rotation_;
115+
double external_detection_translation_x_;
116+
double external_detection_translation_y_;
117+
118+
// Filtering of detected poses
119+
std::shared_ptr<PoseFilter> filter_;
120+
121+
// If not using an external pose reference, this is the distance threshold
122+
double docking_threshold_;
123+
std::string base_frame_id_;
124+
// Offset for staging pose relative to dock pose
125+
double staging_x_offset_;
126+
double staging_yaw_offset_;
127+
128+
rclcpp_lifecycle::LifecycleNode::SharedPtr node_;
129+
std::shared_ptr<tf2_ros::Buffer> tf2_buffer_;
130+
};
131+
132+
} // namespace opennav_docking
133+
134+
#endif // OPENNAV_DOCKING__SIMPLE_NON_CHARGING_DOCK_HPP_

nav2_docking/opennav_docking/plugins.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
<description>A simple charging dock plugin.</description>
55
</class>
66
</library>
7+
<library path="simple_non_charging_dock">
8+
<class type="opennav_docking::SimpleNonChargingDock" base_class_type="opennav_docking_core::ChargingDock">
9+
<description>A simple non-charging dock plugin.</description>
10+
</class>
11+
</library>
712
<library path="test_dock">
813
<class type="opennav_docking::TestFailureDock"
914
base_class_type="opennav_docking_core::ChargingDock">

0 commit comments

Comments
 (0)