19 #include "nav2_bt_navigator/navigators/navigate_to_pose.hpp"
20 #include "nav2_util/path_utils.hpp"
21 #include "nav2_msgs/msg/tracking_feedback.hpp"
22 #include "nav2_ros_common/node_utils.hpp"
24 namespace nav2_bt_navigator
29 nav2::LifecycleNode::WeakPtr parent_node,
30 std::shared_ptr<nav2_util::OdomSmoother> odom_smoother)
32 start_time_ = rclcpp::Time(0);
33 auto node = parent_node.lock();
35 goal_blackboard_id_ = node->declare_or_get_parameter(
36 getName() +
".goal_blackboard_id",
38 path_blackboard_id_ = node->declare_or_get_parameter(
39 getName() +
".path_blackboard_id",
41 tracking_feedback_blackboard_id_ = node->declare_or_get_parameter(
42 getName() +
".tracking_feedback_blackboard_id",
43 std::string(
"tracking_feedback"));
45 search_window_ = node->declare_or_get_parameter(
getName() +
"search_window", 2.0);
46 transform_staleness_threshold_ = node->declare_or_get_parameter(
47 getName() +
".transform_staleness_threshold", 0.0);
50 odom_smoother_ = odom_smoother;
52 self_client_ = node->create_action_client<ActionT>(
getName());
54 goal_sub_ = node->create_subscription<geometry_msgs::msg::PoseStamped>(
58 bool enable_groot_monitoring =
59 node->declare_or_get_parameter(
getName() +
".enable_groot_monitoring",
false);
60 int groot_server_port =
61 node->declare_or_get_parameter(
getName() +
".groot_server_port", 1669);
63 bt_action_server_->setGrootMonitoring(
64 enable_groot_monitoring,
72 nav2::LifecycleNode::WeakPtr parent_node)
74 auto node = parent_node.lock();
75 std::string pkg_share_dir =
76 nav2::get_package_share_directory(
"nav2_bt_navigator");
78 auto default_bt_xml_filename = node->declare_or_get_parameter(
79 "default_nav_to_pose_bt_xml",
81 "/behavior_trees/navigate_to_pose_w_replanning_and_recovery.xml");
83 return default_bt_xml_filename;
102 typename ActionT::Result::SharedPtr result,
103 nav2_behavior_tree::BtStatus & )
105 if (result->error_code == 0) {
106 if (bt_action_server_->populateInternalError(result)) {
109 "NavigateToPoseNavigator::goalCompleted, internal error %d:%s.",
111 result->error_msg.c_str());
115 logger_,
"NavigateToPoseNavigator::goalCompleted error %d:%s.",
117 result->error_msg.c_str());
126 auto feedback_msg = std::make_shared<ActionT::Feedback>();
128 geometry_msgs::msg::PoseStamped current_pose;
129 if (!nav2_util::getFreshPose(
130 *feedback_utils_.tf, feedback_utils_.global_frame,
131 feedback_utils_.robot_frame, clock_->now(),
132 transform_staleness_threshold_, current_pose))
134 RCLCPP_ERROR(logger_,
"Robot pose is not available.");
138 auto blackboard = bt_action_server_->getBlackboard();
141 nav_msgs::msg::Path current_path;
142 auto res = blackboard->get(path_blackboard_id_, current_path);
143 if (res && current_path.poses.size() > 0u) {
145 if (nav2_util::isPathUpdated(current_path, previous_path_) ||
146 nav2_util::isGoalUpdated(current_path, previous_path_) ||
147 previous_path_.poses.size() == 0u)
150 previous_path_ = current_path;
153 const auto path_search_result = nav2_util::distance_from_path(
154 current_path, current_pose.pose, start_index_, search_window_);
157 start_index_ = path_search_result.closest_segment_index;
158 double distance_remaining =
159 nav2_util::geometry_utils::calculate_path_length(current_path, start_index_);
162 rclcpp::Duration estimated_time_remaining = rclcpp::Duration::from_seconds(0.0);
165 geometry_msgs::msg::Twist current_odom = odom_smoother_->getTwist();
166 double current_linear_speed = std::hypot(current_odom.linear.x, current_odom.linear.y);
170 if ((std::abs(current_linear_speed) > 0.01) && (distance_remaining > 0.1)) {
171 estimated_time_remaining =
172 rclcpp::Duration::from_seconds(distance_remaining / std::abs(current_linear_speed));
175 feedback_msg->distance_remaining = distance_remaining;
176 feedback_msg->estimated_time_remaining = estimated_time_remaining;
179 int recovery_count = 0;
180 res = blackboard->get(
"number_recoveries", recovery_count);
181 feedback_msg->number_of_recoveries = recovery_count;
182 feedback_msg->current_pose = current_pose;
183 feedback_msg->navigation_time = clock_->now() - start_time_;
184 nav2_msgs::msg::TrackingFeedback tracking_feedback;
185 res = blackboard->get(
186 tracking_feedback_blackboard_id_,
188 feedback_msg->position_tracking_error = tracking_feedback.position_tracking_error;
189 feedback_msg->heading_tracking_error = tracking_feedback.heading_tracking_error;
191 bt_action_server_->publishFeedback(feedback_msg);
197 RCLCPP_INFO(logger_,
"Received goal preemption request");
199 if (goal->behavior_tree == bt_action_server_->getCurrentBTFilenameOrID() ||
200 (goal->behavior_tree.empty() &&
201 bt_action_server_->getCurrentBTFilenameOrID() == bt_action_server_->getDefaultBTFilenameOrID()))
209 "Preemption request was rejected since the goal pose could not be "
210 "transformed. For now, continuing to track the last goal until completion.");
211 bt_action_server_->terminatePendingGoal();
216 "Preemption request was rejected since the requested BT XML file is not the same "
217 "as the one that the current goal is executing. Preemption with a new BT is invalid "
218 "since it would require cancellation of the previous goal instead of true preemption."
219 "\nCancel the current goal and send a new action request if you want to use a "
220 "different BT XML file. For now, continuing to track the last goal until completion.");
221 bt_action_server_->terminatePendingGoal();
228 geometry_msgs::msg::PoseStamped current_pose;
229 if (!nav2_util::getFreshPose(
230 *feedback_utils_.tf, feedback_utils_.global_frame,
231 feedback_utils_.robot_frame, clock_->now(),
232 transform_staleness_threshold_, current_pose))
234 bt_action_server_->setInternalError(
235 ActionT::Result::TF_ERROR,
236 "Initial robot pose is not available.");
240 geometry_msgs::msg::PoseStamped goal_pose;
241 if (!nav2_util::transformPoseInTargetFrame(
242 goal->pose, goal_pose, *feedback_utils_.tf, feedback_utils_.global_frame,
243 feedback_utils_.transform_tolerance))
245 bt_action_server_->setInternalError(
246 ActionT::Result::TF_ERROR,
247 "Failed to transform a goal pose provided with frame_id '" +
248 goal->pose.header.frame_id +
249 "' to the global frame '" +
250 feedback_utils_.global_frame +
256 logger_,
"Begin navigating from current location (%.2f, %.2f) to (%.2f, %.2f)",
257 current_pose.pose.position.x, current_pose.pose.position.y,
258 goal_pose.pose.position.x, goal_pose.pose.position.y);
261 start_time_ = clock_->now();
262 auto blackboard = bt_action_server_->getBlackboard();
263 blackboard->set(
"number_recoveries", 0);
264 previous_path_ = nav_msgs::msg::Path();
267 blackboard->set(goal_blackboard_id_, goal_pose);
268 blackboard->set(path_blackboard_id_, nav_msgs::msg::Path());
275 const geometry_msgs::msg::PoseStamped::ConstSharedPtr & pose)
279 self_client_->async_send_goal(goal);
284 #include "pluginlib/class_list_macros.hpp"
285 PLUGINLIB_EXPORT_CLASS(
A navigator for navigating to a specified pose.
void onPreempt(ActionT::Goal::ConstSharedPtr goal) override
A callback that is called when a preempt is requested.
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 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 initializeGoalPose(ActionT::Goal::ConstSharedPtr goal)
Goal pose initialization on the blackboard.
bool configure(nav2::LifecycleNode::WeakPtr node, std::shared_ptr< nav2_util::OdomSmoother > odom_smoother) override
A configure state transition to configure navigator's state.
std::string getName() override
Get action name for this navigator.
std::string getDefaultBTFilepath(nav2::LifecycleNode::WeakPtr node) override
Get navigator's default BT.
void onGoalPoseReceived(const geometry_msgs::msg::PoseStamped::ConstSharedPtr &pose)
A subscription and callback to handle the topic-based goal published from rviz.
void onLoop() override
A callback that defines execution that happens on one iteration through the BT Can be used to publish...
bool cleanup() override
A cleanup state transition to remove memory allocated.
Navigator interface to allow navigators to be stored in a vector and accessed via pluginlib due to te...