15 #include "nav2_route/route_tracker.hpp"
17 #include "nav2_ros_common/rate.hpp"
18 #include "nav2_ros_common/tf2_factories.hpp"
24 nav2::LifecycleNode::SharedPtr node,
25 nav2::TransformBuffer::SharedPtr tf_buffer,
26 std::shared_ptr<nav2_costmap_2d::CostmapSubscriber> costmap_subscriber,
27 std::shared_ptr<ActionServerTrack> action_server,
28 const std::string & route_frame,
29 const std::string & base_frame)
32 clock_ = node->get_clock();
33 logger_ = node->get_logger();
34 route_frame_ = route_frame;
35 base_frame_ = base_frame;
36 action_server_ = action_server;
37 tf_buffer_ = tf_buffer;
39 radius_threshold_ = node->declare_or_get_parameter(
"radius_to_achieve_node", 2.0);
40 boundary_radius_threshold_ = node->declare_or_get_parameter(
41 "boundary_radius_to_achieve_node", 1.0);
42 tracker_update_rate_ = node->declare_or_get_parameter(
"tracker_update_rate", 50.0);
43 aggregate_blocked_ids_ = node->declare_or_get_parameter(
44 "aggregate_blocked_ids",
false);
46 operations_manager_ = std::make_unique<OperationsManager>(node, costmap_subscriber);
51 geometry_msgs::msg::PoseStamped pose;
52 if (!nav2_util::getCurrentPose(pose, *tf_buffer_, route_frame_, base_frame_)) {
59 const geometry_msgs::msg::PoseStamped & pose,
64 const double dx = state.next_node->coords.x - pose.pose.position.x;
65 const double dy = state.next_node->coords.y - pose.pose.position.y;
66 const double dist_mag = std::sqrt(dx * dx + dy * dy);
68 const bool in_radius =
69 (dist_mag <= (is_boundary_node ? boundary_radius_threshold_ : radius_threshold_));
72 if (dist_mag < 1e-4 || (!in_radius && state.within_radius)) {
77 state.within_radius = in_radius;
82 if (is_boundary_node) {
83 return state.within_radius;
93 if (state.within_radius) {
94 NodePtr last_node = state.current_edge->start;
95 const double nx = state.next_node->coords.x - last_node->coords.x;
96 const double ny = state.next_node->coords.y - last_node->coords.y;
97 const double n_mag = std::sqrt(nx * nx + ny * ny);
99 NodePtr future_next_node = route.edges[state.route_edges_idx + 1]->end;
100 const double mx = future_next_node->coords.x - state.next_node->coords.x;
101 const double my = future_next_node->coords.y - state.next_node->coords.y;
102 const double m_mag = std::sqrt(mx * mx + my * my);
105 if (n_mag < 1e-6 || m_mag < 1e-6) {
110 const double bx = nx * m_mag + mx * n_mag;
111 const double by = ny * m_mag + my * n_mag;
112 return utils::normalizedDot(bx, by, dx, dy) <= 0;
123 (state.route_edges_idx ==
static_cast<int>(route.edges.size() - 1)) ||
124 (state.route_edges_idx == -1 && !state.current_edge);
128 const bool rereouted,
129 const unsigned int next_node_id,
130 const unsigned int last_node_id,
131 const unsigned int edge_id,
132 const std::vector<std::string> & operations)
134 auto feedback = std::make_unique<Feedback>();
135 feedback->route = route_msg_;
136 feedback->path = path_;
137 feedback->rerouted = rereouted;
138 feedback->next_node_id = next_node_id;
139 feedback->last_node_id = last_node_id;
140 feedback->current_edge_id = edge_id;
141 feedback->operations_triggered = operations;
142 action_server_->publish_feedback(std::move(feedback));
146 const Route & route,
const nav_msgs::msg::Path & path,
149 route_msg_ = utils::toMsg(route, route_frame_, clock_->now());
152 state.next_node = route.start_node;
157 if (rerouting_info.curr_edge) {
162 state.current_edge = rerouting_info.curr_edge;
163 state.last_node = state.current_edge->start;
165 true, route.start_node->nodeid, state.last_node->nodeid, state.current_edge->edgeid, {});
170 auto node = node_.lock();
176 while (rclcpp::ok()) {
177 bool status_change =
false, completed =
false;
180 if (action_server_->is_cancel_requested()) {
181 return TrackerResult::INTERRUPTED;
182 }
else if (action_server_->is_preempt_requested()) {
183 return TrackerResult::INTERRUPTED;
187 geometry_msgs::msg::PoseStamped robot_pose =
getRobotPose();
189 status_change =
true;
190 state.within_radius =
false;
191 state.last_node = state.next_node;
192 if (++state.route_edges_idx <
static_cast<int>(route.edges.size())) {
193 state.current_edge = route.edges[state.route_edges_idx];
194 state.next_node = state.current_edge->end;
196 state.current_edge =
nullptr;
197 state.next_node =
nullptr;
204 operations_manager_->process(status_change, state, route, robot_pose, rerouting_info);
207 RCLCPP_INFO(logger_,
"Routing to goal completed!");
209 publishFeedback(
false, 0, state.last_node->nodeid, 0, ops_result.operations_triggered);
210 return TrackerResult::COMPLETED;
213 if ((status_change || !ops_result.operations_triggered.empty()) && state.current_edge) {
216 state.next_node->nodeid, state.last_node->nodeid,
217 state.current_edge->edgeid, ops_result.operations_triggered);
220 if (ops_result.reroute) {
221 if (!aggregate_blocked_ids_) {
222 rerouting_info.blocked_ids = ops_result.blocked_ids;
224 rerouting_info.blocked_ids.insert(
225 rerouting_info.blocked_ids.end(),
226 ops_result.blocked_ids.begin(), ops_result.blocked_ids.end());
229 if (state.last_node) {
230 rerouting_info.rerouting_start_id = state.last_node->nodeid;
231 rerouting_info.rerouting_start_pose = robot_pose;
233 rerouting_info.rerouting_start_id = std::numeric_limits<unsigned int>::max();
234 rerouting_info.rerouting_start_pose = geometry_msgs::msg::PoseStamped();
238 rerouting_info.curr_edge = state.current_edge;
239 RCLCPP_INFO(logger_,
"Rerouting requested by route tracking operations!");
240 return TrackerResult::INTERRUPTED;
246 return TrackerResult::EXITED;
A sim-time-aware rate for Nav2 loops.
void configure(nav2::LifecycleNode::SharedPtr node, nav2::TransformBuffer::SharedPtr tf_buffer, std::shared_ptr< nav2_costmap_2d::CostmapSubscriber > costmap_subscriber, typename ActionServerTrack::SharedPtr action_server, const std::string &route_frame, const std::string &base_frame)
Configure route tracker.
bool nodeAchieved(const geometry_msgs::msg::PoseStamped &pose, RouteTrackingState &state, const Route &route)
Determine if a node is to be considered achieved at the current position.
TrackerResult trackRoute(const Route &route, const nav_msgs::msg::Path &path, ReroutingState &rerouting_info)
Main function to track route, manage state, and trigger operations.
void publishFeedback(const bool rereouted, const unsigned int next_node_id, const unsigned int last_node_id, const unsigned int edge_id, const std::vector< std::string > &operations)
A utility to publish feedback for the action on important changes.
geometry_msgs::msg::PoseStamped getRobotPose()
Get the current robot's base_frame pose in route_frame.
bool isStartOrEndNode(RouteTrackingState &state, const Route &route)
Determine if a node is the start or last node in the route.
An object to store the nodes in the graph file.
Result information from the operations manager.
State shared to objects to communicate important rerouting data to avoid rerouting over blocked edges...
Current state management of route tracking class.
An ordered set of nodes and edges corresponding to the planned route.