21 #include "nav2_bt_navigator/navigators/navigate_through_poses.hpp"
22 #include "nav2_util/path_utils.hpp"
23 #include "nav2_msgs/msg/tracking_feedback.hpp"
24 #include "nav2_ros_common/node_utils.hpp"
26 namespace nav2_bt_navigator
31 nav2::LifecycleNode::WeakPtr parent_node,
32 std::shared_ptr<nav2_util::OdomSmoother> odom_smoother)
34 start_time_ = rclcpp::Time(0);
35 auto node = parent_node.lock();
37 goals_blackboard_id_ =
38 node->declare_or_get_parameter(
getName() +
".goals_blackboard_id", std::string(
"goals"));
40 node->declare_or_get_parameter(
getName() +
".path_blackboard_id", std::string(
"path"));
41 tracking_feedback_blackboard_id_ = node->declare_or_get_parameter(
42 getName() +
".tracking_feedback_blackboard_id",
43 std::string(
"tracking_feedback"));
44 waypoint_statuses_blackboard_id_ =
45 node->declare_or_get_parameter(
46 getName() +
".waypoint_statuses_blackboard_id",
47 std::string(
"waypoint_statuses"));
49 search_window_ = node->declare_or_get_parameter(
getName() +
"search_window", 2.0);
50 transform_staleness_threshold_ = node->declare_or_get_parameter(
51 getName() +
".transform_staleness_threshold", 0.0);
54 odom_smoother_ = odom_smoother;
56 bool enable_groot_monitoring =
57 node->declare_or_get_parameter(
getName() +
".enable_groot_monitoring",
false);
58 int groot_server_port =
59 node->declare_or_get_parameter(
getName() +
".groot_server_port", 1669);
61 bt_action_server_->setGrootMonitoring(
62 enable_groot_monitoring,
70 nav2::LifecycleNode::WeakPtr parent_node)
72 auto node = parent_node.lock();
73 std::string pkg_share_dir =
74 nav2::get_package_share_directory(
"nav2_bt_navigator");
76 auto default_bt_xml_filename = node->declare_or_get_parameter(
77 "default_nav_through_poses_bt_xml",
79 "/behavior_trees/navigate_through_poses_w_replanning_and_recovery.xml");
81 return default_bt_xml_filename;
92 typename ActionT::Result::SharedPtr result,
93 nav2_behavior_tree::BtStatus & final_bt_status)
95 if (result->error_code == 0) {
96 if (bt_action_server_->populateInternalError(result)) {
99 "NavigateThroughPosesNavigator::goalCompleted, internal error %d:'%s'.",
101 result->error_msg.c_str());
105 logger_,
"NavigateThroughPosesNavigator::goalCompleted error %d:'%s'.",
107 result->error_msg.c_str());
111 auto blackboard = bt_action_server_->getBlackboard();
112 auto waypoint_statuses =
113 blackboard->get<std::vector<nav2_msgs::msg::WaypointStatus>>(waypoint_statuses_blackboard_id_);
116 auto integrate_waypoint_status = final_bt_status == nav2_behavior_tree::BtStatus::SUCCEEDED ?
117 nav2_msgs::msg::WaypointStatus::COMPLETED : nav2_msgs::msg::WaypointStatus::FAILED;
118 for (
auto & waypoint_status : waypoint_statuses) {
119 if (waypoint_status.waypoint_status == nav2_msgs::msg::WaypointStatus::PENDING) {
120 waypoint_status.waypoint_status = integrate_waypoint_status;
124 result->waypoint_statuses = std::move(waypoint_statuses);
130 using namespace nav2_util::geometry_utils;
134 auto feedback_msg = std::make_shared<ActionT::Feedback>();
136 auto blackboard = bt_action_server_->getBlackboard();
138 nav_msgs::msg::Goals goal_poses;
139 [[maybe_unused]]
auto res = blackboard->get(goals_blackboard_id_, goal_poses);
141 feedback_msg->waypoint_statuses =
142 blackboard->get<std::vector<nav2_msgs::msg::WaypointStatus>>(waypoint_statuses_blackboard_id_);
144 if (goal_poses.goals.size() == 0) {
145 bt_action_server_->publishFeedback(feedback_msg);
149 geometry_msgs::msg::PoseStamped current_pose;
150 if (!nav2_util::getFreshPose(
151 *feedback_utils_.tf, feedback_utils_.global_frame,
152 feedback_utils_.robot_frame, clock_->now(),
153 transform_staleness_threshold_, current_pose))
155 RCLCPP_ERROR(logger_,
"Robot pose is not available.");
160 nav_msgs::msg::Path current_path;
161 res = blackboard->get(path_blackboard_id_, current_path);
162 if (res && current_path.poses.size() > 0u) {
164 if (nav2_util::isPathUpdated(current_path, previous_path_) ||
165 nav2_util::isGoalUpdated(current_path, previous_path_) ||
166 previous_path_.poses.size() == 0u)
169 previous_path_ = current_path;
172 const auto path_search_result = nav2_util::distance_from_path(
173 current_path, current_pose.pose, start_index_, search_window_);
176 start_index_ = path_search_result.closest_segment_index;
177 double distance_remaining =
178 nav2_util::geometry_utils::calculate_path_length(current_path, start_index_);
181 rclcpp::Duration estimated_time_remaining = rclcpp::Duration::from_seconds(0.0);
184 geometry_msgs::msg::Twist current_odom = odom_smoother_->getTwist();
185 double current_linear_speed = std::hypot(current_odom.linear.x, current_odom.linear.y);
189 if ((std::abs(current_linear_speed) > 0.01) && (distance_remaining > 0.1)) {
190 estimated_time_remaining =
191 rclcpp::Duration::from_seconds(distance_remaining / std::abs(current_linear_speed));
194 feedback_msg->distance_remaining = distance_remaining;
195 feedback_msg->estimated_time_remaining = estimated_time_remaining;
198 int recovery_count = 0;
199 res = blackboard->get(
"number_recoveries", recovery_count);
200 feedback_msg->number_of_recoveries = recovery_count;
201 feedback_msg->current_pose = current_pose;
202 feedback_msg->navigation_time = clock_->now() - start_time_;
203 feedback_msg->number_of_poses_remaining = goal_poses.goals.size();
204 nav2_msgs::msg::TrackingFeedback tracking_feedback;
205 res = blackboard->get(
206 tracking_feedback_blackboard_id_,
208 feedback_msg->position_tracking_error = tracking_feedback.position_tracking_error;
209 feedback_msg->heading_tracking_error = tracking_feedback.heading_tracking_error;
211 bt_action_server_->publishFeedback(feedback_msg);
217 RCLCPP_INFO(logger_,
"Received goal preemption request");
219 if (goal->behavior_tree == bt_action_server_->getCurrentBTFilenameOrID() ||
220 (goal->behavior_tree.empty() &&
221 bt_action_server_->getCurrentBTFilenameOrID() == bt_action_server_->getDefaultBTFilenameOrID()))
227 throw std::runtime_error(
228 "Preemption request was rejected since the goal poses could not be "
234 "Preemption request was rejected since the requested BT XML file is not the same "
235 "as the one that the current goal is executing. Preemption with a new BT is invalid "
236 "since it would require cancellation of the previous goal instead of true preemption."
237 "\nCancel the current goal and send a new action request if you want to use a "
238 "different BT XML file. For now, continuing to track the last goal until completion.");
239 bt_action_server_->terminatePendingGoal();
246 geometry_msgs::msg::PoseStamped current_pose;
247 if (!nav2_util::getFreshPose(
248 *feedback_utils_.tf, feedback_utils_.global_frame,
249 feedback_utils_.robot_frame, clock_->now(),
250 transform_staleness_threshold_, current_pose))
252 bt_action_server_->setInternalError(
253 ActionT::Result::TF_ERROR,
254 "Initial robot pose is not available.");
258 nav_msgs::msg::Goals goals_array = goal->poses;
260 for (
auto & goal_pose : goals_array.goals) {
261 if (!nav2_util::transformPoseInTargetFrame(
262 goal_pose, goal_pose, *feedback_utils_.tf, feedback_utils_.global_frame,
263 feedback_utils_.transform_tolerance))
265 bt_action_server_->setInternalError(
266 ActionT::Result::TF_ERROR,
267 "Failed to transform a goal pose (" + std::to_string(i) +
") provided with frame_id '" +
268 goal_pose.header.frame_id +
269 "' to the global frame '" +
270 feedback_utils_.global_frame +
277 if (goals_array.goals.size() > 0) {
279 logger_,
"Begin navigating from current location through %zu poses to (%.2f, %.2f)",
280 goals_array.goals.size(), goals_array.goals.back().pose.position.x,
281 goals_array.goals.back().pose.position.y);
285 start_time_ = clock_->now();
286 auto blackboard = bt_action_server_->getBlackboard();
287 blackboard->set(
"number_recoveries", 0);
288 previous_path_ = nav_msgs::msg::Path();
291 blackboard->set<nav_msgs::msg::Goals>(
292 goals_blackboard_id_,
293 std::move(goals_array));
294 blackboard->set<nav_msgs::msg::Path>(
296 nav_msgs::msg::Path());
299 std::vector<nav2_msgs::msg::WaypointStatus> waypoint_statuses(goals_array.goals.size());
300 for (
size_t waypoint_index = 0; waypoint_index < goals_array.goals.size(); ++waypoint_index) {
301 waypoint_statuses[waypoint_index].waypoint_index = waypoint_index;
302 waypoint_statuses[waypoint_index].waypoint_pose = goals_array.goals[waypoint_index];
304 blackboard->set<decltype(waypoint_statuses)>(
305 waypoint_statuses_blackboard_id_,
306 std::move(waypoint_statuses));
313 #include "pluginlib/class_list_macros.hpp"
314 PLUGINLIB_EXPORT_CLASS(
A navigator for navigating to a a bunch of intermediary poses.
void goalCompleted(typename ActionT::Result::SharedPtr result, nav2_behavior_tree::BtStatus &final_bt_status) override
A callback that is called when a the action is completed, can fill in action result message or indica...
bool configure(nav2::LifecycleNode::WeakPtr node, std::shared_ptr< nav2_util::OdomSmoother > odom_smoother) override
A configure state transition to configure navigator's state.
void onPreempt(ActionT::Goal::ConstSharedPtr goal) override
A callback that is called when a preempt is requested.
std::string getName() override
Get action name for this navigator.
bool goalReceived(ActionT::Goal::ConstSharedPtr goal) override
A callback to be called when a new goal is received by the BT action server Can be used to check if g...
bool initializeGoalPoses(ActionT::Goal::ConstSharedPtr goal)
Goal pose initialization on the blackboard.
std::string getDefaultBTFilepath(nav2::LifecycleNode::WeakPtr node) override
Get navigator's default BT.
void onLoop() override
A callback that defines execution that happens on one iteration through the BT Can be used to publish...
Navigator interface to allow navigators to be stored in a vector and accessed via pluginlib due to te...