Skip to content

Commit 74d4d46

Browse files
committed
Adding path change checks
Signed-off-by: silanus23 <berkantali23@outlook.com>
1 parent 503c0f1 commit 74d4d46

3 files changed

Lines changed: 100 additions & 7 deletions

File tree

nav2_costmap_2d/include/nav2_costmap_2d/bounded_tracking_error_layer.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ class BoundedTrackingErrorLayer : public nav2_costmap_2d::Layer
151151
*/
152152
void trackingCallback(const nav2_msgs::msg::TrackingFeedback::SharedPtr msg);
153153

154+
/**
155+
* @brief Callback for goal pose updates.
156+
* @param msg Incoming goal pose message.
157+
*/
158+
void goalCallback(const geometry_msgs::msg::PoseStamped::SharedPtr msg);
159+
154160
/**
155161
* @brief Callback for dynamic parameter updates.
156162
* @param parameters Vector of parameters being updated.
@@ -164,8 +170,10 @@ class BoundedTrackingErrorLayer : public nav2_costmap_2d::Layer
164170
private:
165171
nav2::Subscription<nav_msgs::msg::Path>::SharedPtr path_sub_;
166172
nav2::Subscription<nav2_msgs::msg::TrackingFeedback>::SharedPtr tracking_feedback_sub_;
173+
nav2::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr goal_sub_;
167174
std::mutex data_mutex_;
168175
nav_msgs::msg::Path last_path_;
176+
geometry_msgs::msg::PoseStamped last_goal_;
169177
rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr dyn_params_handler_;
170178

171179
size_t step_size_;

nav2_costmap_2d/plugins/bounded_tracking_error_layer.cpp

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void BoundedTrackingErrorLayer::onInitialize()
5151

5252
wall_thickness_ = node->declare_or_get_parameter(name_ + "." + "wall_thickness", 1);
5353

54-
int corridor_cost_param = node->declare_or_get_parameter(name_ + "." + "corridor_cost", 250);
54+
int corridor_cost_param = node->declare_or_get_parameter(name_ + "." + "corridor_cost", 190);
5555
corridor_cost_ = static_cast<unsigned char>(std::clamp(corridor_cost_param, 1, 254));
5656

5757
bool enabled_param = node->declare_or_get_parameter(name_ + "." + "enabled", true);
@@ -87,12 +87,54 @@ void BoundedTrackingErrorLayer::onInitialize()
8787
nav2::qos::StandardTopicQoS()
8888
);
8989

90+
goal_sub_ = node->create_subscription<geometry_msgs::msg::PoseStamped>(
91+
"goal_pose",
92+
std::bind(&BoundedTrackingErrorLayer::goalCallback, this, std::placeholders::_1),
93+
nav2::qos::StandardTopicQoS()
94+
);
95+
9096
dyn_params_handler_ = node->add_on_set_parameters_callback(
9197
std::bind(
9298
&BoundedTrackingErrorLayer::dynamicParametersCallback,
9399
this, std::placeholders::_1));
94100
}
95101

102+
void BoundedTrackingErrorLayer::goalCallback(const geometry_msgs::msg::PoseStamped::SharedPtr msg)
103+
{
104+
auto node = node_.lock();
105+
if (!node) {
106+
return;
107+
}
108+
109+
std::lock_guard<std::mutex> lock(data_mutex_);
110+
111+
// Check if this is a new goal (different position from last goal)
112+
bool is_new_goal = false;
113+
if (last_goal_.header.frame_id.empty()) {
114+
is_new_goal = true;
115+
} else {
116+
double dx = msg->pose.position.x - last_goal_.pose.position.x;
117+
double dy = msg->pose.position.y - last_goal_.pose.position.y;
118+
double distance = std::hypot(dx, dy);
119+
120+
if (distance > 0.1) {
121+
is_new_goal = true;
122+
}
123+
}
124+
125+
if (is_new_goal) {
126+
RCLCPP_DEBUG(
127+
node->get_logger(),
128+
"New goal received, clearing corridor");
129+
130+
// Clear corridor data
131+
last_path_ = nav_msgs::msg::Path();
132+
last_tracking_feedback_ = nav2_msgs::msg::TrackingFeedback();
133+
}
134+
135+
last_goal_ = *msg;
136+
}
137+
96138
void BoundedTrackingErrorLayer::pathCallback(const nav_msgs::msg::Path::SharedPtr msg)
97139
{
98140
auto node = node_.lock();
@@ -114,6 +156,52 @@ void BoundedTrackingErrorLayer::pathCallback(const nav_msgs::msg::Path::SharedPt
114156
last_path_ = nav_msgs::msg::Path();
115157
return;
116158
}
159+
160+
// Check for path discontinuity (replanning detection)
161+
bool path_discontinuity = false;
162+
if (!last_path_.poses.empty() && msg->poses.size() >= 2) {
163+
size_t old_size = last_path_.poses.size();
164+
size_t new_size = msg->poses.size();
165+
166+
if (old_size != new_size) {
167+
path_discontinuity = true;
168+
RCLCPP_DEBUG(
169+
node->get_logger(),
170+
"Path size changed from %zu to %zu, clearing corridor", old_size, new_size);
171+
} else if (old_size >= 2) {
172+
double threshold = corridor_width_ * 0.5;
173+
174+
// Compare points if size stays same and points change
175+
176+
size_t old_mid_idx = old_size / 2;
177+
size_t new_mid_idx = new_size / 2;
178+
double mid_dx = msg->poses[new_mid_idx].pose.position.x -
179+
last_path_.poses[old_mid_idx].pose.position.x;
180+
double mid_dy = msg->poses[new_mid_idx].pose.position.y -
181+
last_path_.poses[old_mid_idx].pose.position.y;
182+
double mid_dist = std::hypot(mid_dx, mid_dy);
183+
184+
double end_dx = msg->poses.back().pose.position.x -
185+
last_path_.poses.back().pose.position.x;
186+
double end_dy = msg->poses.back().pose.position.y -
187+
last_path_.poses.back().pose.position.y;
188+
double end_dist = std::hypot(end_dx, end_dy);
189+
190+
if (mid_dist > threshold || end_dist > threshold) {
191+
path_discontinuity = true;
192+
RCLCPP_DEBUG(
193+
node->get_logger(),
194+
"Path discontinuity detected (mid: %.2fm, end: %.2fm), clearing corridor",
195+
mid_dist, end_dist);
196+
}
197+
}
198+
}
199+
200+
if (path_discontinuity) {
201+
// Clear corridor on replanning
202+
last_tracking_feedback_ = nav2_msgs::msg::TrackingFeedback();
203+
}
204+
117205
last_path_ = *msg;
118206
last_tracking_feedback_ = nav2_msgs::msg::TrackingFeedback();
119207
}
@@ -172,7 +260,6 @@ WallPolygons BoundedTrackingErrorLayer::getWallPolygons(
172260
double outer_half_width = corridor_width_ * 0.5;
173261
double inner_half_width = (corridor_width_ - (wall_thickness_ * resolution * 2.0)) * 0.5;
174262

175-
// Reserve space for efficiency
176263
size_t estimated_points = (segment.poses.size() / step_size_) + 1;
177264
walls.left_outer.reserve(estimated_points);
178265
walls.left_inner.reserve(estimated_points);
@@ -187,7 +274,6 @@ WallPolygons BoundedTrackingErrorLayer::getWallPolygons(
187274
double px = current_pose.pose.position.x;
188275
double py = current_pose.pose.position.y;
189276

190-
// Only draw corridor if we have enough lookahead distance
191277
if (current_index + step_size_ >= segment.poses.size()) {
192278
break;
193279
}
@@ -205,7 +291,6 @@ WallPolygons BoundedTrackingErrorLayer::getWallPolygons(
205291
double perp_x = -dy / norm;
206292
double perp_y = dx / norm;
207293

208-
// Calculate all 4 points at this location
209294
walls.left_outer.push_back({px + perp_x * outer_half_width, py + perp_y * outer_half_width});
210295
walls.left_inner.push_back({px + perp_x * inner_half_width, py + perp_y * inner_half_width});
211296
walls.right_outer.push_back({px - perp_x * outer_half_width, py - perp_y * outer_half_width});
@@ -284,7 +369,7 @@ void BoundedTrackingErrorLayer::updateCosts(
284369
transformed_segment.header.frame_id = costmap_frame;
285370
transformed_segment.poses.reserve(segment.poses.size());
286371

287-
// Use longer timeout for first pose to wait for TF, no wait for rest
372+
// Use longer timeout for first pose to wait for TF
288373
for (size_t i = 0; i < segment.poses.size(); ++i) {
289374
const auto & pose = segment.poses[i];
290375
geometry_msgs::msg::PoseStamped transformed_pose;
@@ -451,6 +536,7 @@ void BoundedTrackingErrorLayer::deactivate()
451536
std::lock_guard<std::mutex> lock(data_mutex_);
452537
last_path_ = nav_msgs::msg::Path();
453538
last_tracking_feedback_ = nav2_msgs::msg::TrackingFeedback();
539+
last_goal_ = geometry_msgs::msg::PoseStamped();
454540
}
455541

456542
enabled_.store(false);

nav2_costmap_2d/test/unit/bounded_tracking_error_layer_test.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class BoundedTrackingErrorLayerTestFixture : public ::testing::Test
132132
feedback.header.frame_id = "map";
133133
feedback.header.stamp = node_->now();
134134
feedback.current_path_index = path_index;
135-
feedback.tracking_error = error;
135+
feedback.position_tracking_error = error;
136136

137137
feedback.robot_pose.header = feedback.header;
138138
feedback.robot_pose.pose.position.x = path_index * 0.1;
@@ -203,7 +203,6 @@ TEST_F(BoundedTrackingErrorLayerTestFixture, test_path_segment_bounds)
203203
EXPECT_FALSE(segment.poses.empty());
204204
EXPECT_LT(segment.poses.size(), path.poses.size());
205205

206-
// Check segment boundaries make sense
207206
double first_x = segment.poses.front().pose.position.x;
208207
double last_x = segment.poses.back().pose.position.x;
209208
double robot_x = tracking_error.robot_pose.pose.position.x;

0 commit comments

Comments
 (0)