40~60s完赛

This commit is contained in:
2026-08-10 15:48:25 +08:00
parent 07598f4b11
commit b3d06e1ba8
5 changed files with 104 additions and 9 deletions

View File

@@ -102,7 +102,7 @@ controller_server:
GoalCritic: GoalCritic:
enabled: true enabled: true
cost_power: 1 cost_power: 1
cost_weight: 6.0 cost_weight: 5.0
threshold_to_consider: 1.4 threshold_to_consider: 1.4
GoalAngleCritic: GoalAngleCritic:
enabled: true enabled: true
@@ -126,7 +126,7 @@ controller_server:
PathAlignCritic: PathAlignCritic:
enabled: true enabled: true
cost_power: 1 cost_power: 1
cost_weight: 8.0 cost_weight: 10.0
max_path_occupancy_ratio: 0.05 max_path_occupancy_ratio: 0.05
trajectory_point_step: 4 trajectory_point_step: 4
threshold_to_consider: 0.5 threshold_to_consider: 0.5
@@ -224,8 +224,8 @@ global_costmap:
extra_inflation: 0.02 extra_inflation: 0.02
inflation_layer: inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer" plugin: "nav2_costmap_2d::InflationLayer"
cost_scaling_factor: 2.0 cost_scaling_factor: 3.0
inflation_radius: 0.35 inflation_radius: 0.30
always_send_full_costmap: True always_send_full_costmap: True
global_costmap_client: global_costmap_client:
ros__parameters: ros__parameters:
@@ -252,10 +252,10 @@ planner_server:
analytic_expansion_ratio: 3.5 analytic_expansion_ratio: 3.5
analytic_expansion_max_length: 3.0 analytic_expansion_max_length: 3.0
minimum_turning_radius: 0.40 minimum_turning_radius: 0.40
reverse_penalty: 1.6 reverse_penalty: 2.0
change_penalty: 2.0 change_penalty: 1.0
non_straight_penalty: 1.2 non_straight_penalty: 1.2
cost_penalty: 4.0 cost_penalty: 3.0
retrospective_penalty: 0.015 retrospective_penalty: 0.015
# 5 m covers the rolling planning horizon without the startup and memory # 5 m covers the rolling planning horizon without the startup and memory
# cost of the previous 20 m (401-cell) Hybrid-A* lookup table. # cost of the previous 20 m (401-cell) Hybrid-A* lookup table.

View File

@@ -5,7 +5,7 @@ racing_control:
frame_id: odom frame_id: odom
use_post_qr_pose: false use_post_qr_pose: false
enable_vlm_image_relay: false enable_vlm_image_relay: false
enable_dynamic_replanning: true enable_dynamic_replanning: false
enable_recovery: true enable_recovery: true
vlm_image_input_topic: /image vlm_image_input_topic: /image
vlm_image_output_topic: /vlm_image vlm_image_output_topic: /vlm_image

View File

@@ -3,6 +3,7 @@
#include <cmath> #include <cmath>
#include <cctype> #include <cctype>
#include <cstddef>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -153,6 +154,38 @@ inline geometry_msgs::msg::PoseStamped poseFromXYYaw(
return pose; return pose;
} }
inline double poseDistance2d(
const geometry_msgs::msg::PoseStamped & a,
const geometry_msgs::msg::PoseStamped & b)
{
const auto dx = a.pose.position.x - b.pose.position.x;
const auto dy = a.pose.position.y - b.pose.position.y;
return std::hypot(dx, dy);
}
inline std::size_t advanceReachedWaypointIndex(
const std::vector<geometry_msgs::msg::PoseStamped> & waypoints,
const geometry_msgs::msg::PoseStamped & current,
const std::size_t next_waypoint_index,
const double tolerance)
{
auto next = next_waypoint_index;
while (next < waypoints.size() && poseDistance2d(current, waypoints[next]) <= tolerance) {
++next;
}
return next;
}
inline std::vector<geometry_msgs::msg::PoseStamped> remainingWaypoints(
const std::vector<geometry_msgs::msg::PoseStamped> & waypoints,
const std::size_t next_waypoint_index)
{
if (next_waypoint_index >= waypoints.size()) {
return {};
}
return {waypoints.begin() + static_cast<std::ptrdiff_t>(next_waypoint_index), waypoints.end()};
}
inline std::vector<geometry_msgs::msg::PoseStamped> posesFromFlatDoubles( inline std::vector<geometry_msgs::msg::PoseStamped> posesFromFlatDoubles(
const std::vector<double> & values, const std::string & frame_id) const std::vector<double> & values, const std::string & frame_id)
{ {

View File

@@ -616,6 +616,7 @@ private:
if (vlm_capture_mode_ == VlmCaptureMode::PassThrough) { if (vlm_capture_mode_ == VlmCaptureMode::PassThrough) {
active_segment_ = RouteSegment::FullRoute; active_segment_ = RouteSegment::FullRoute;
active_segment_waypoints_ = route.waypoints; active_segment_waypoints_ = route.waypoints;
active_segment_next_waypoint_index_ = 0;
runRouteSegmentPlanning("full route with pass-through VLM capture"); runRouteSegmentPlanning("full route with pass-through VLM capture");
return; return;
} }
@@ -624,6 +625,7 @@ private:
active_segment_waypoints_.assign( active_segment_waypoints_.assign(
route.waypoints.begin(), route.waypoints.begin(),
route.waypoints.begin() + vlm_index + 1); route.waypoints.begin() + vlm_index + 1);
active_segment_next_waypoint_index_ = 0;
runRouteSegmentPlanning("to VLM waypoint"); runRouteSegmentPlanning("to VLM waypoint");
} }
@@ -640,6 +642,7 @@ private:
active_segment_waypoints_.assign( active_segment_waypoints_.assign(
route.waypoints.begin() + vlm_index + 1, route.waypoints.begin() + vlm_index + 1,
route.waypoints.end()); route.waypoints.end());
active_segment_next_waypoint_index_ = 0;
runRouteSegmentPlanning("after VLM waypoint"); runRouteSegmentPlanning("after VLM waypoint");
} }
@@ -809,6 +812,10 @@ private:
if (!current) { if (!current) {
return; return;
} }
updateActiveSegmentWaypointProgress(*current);
if (active_segment_next_waypoint_index_ >= active_segment_waypoints_.size()) {
return;
}
const auto distance_to_goal = distance2d(*current, active_segment_waypoints_.back()); const auto distance_to_goal = distance2d(*current, active_segment_waypoints_.back());
const auto elapsed = (now() - last_dynamic_replan_time_).seconds(); const auto elapsed = (now() - last_dynamic_replan_time_).seconds();
if (!shouldDynamicReplan( if (!shouldDynamicReplan(
@@ -830,8 +837,15 @@ private:
return; return;
} }
const auto replan_goals = remainingWaypoints(
active_segment_waypoints_, active_segment_next_waypoint_index_);
if (replan_goals.empty()) {
dynamic_replan_in_flight_ = false;
return;
}
ComputePathThroughPoses::Goal goal; ComputePathThroughPoses::Goal goal;
goal.goals = stampPoses({active_segment_waypoints_.back()}); goal.goals = stampPoses(replan_goals);
goal.planner_id = planner_id_; goal.planner_id = planner_id_;
goal.use_start = false; goal.use_start = false;
@@ -864,6 +878,22 @@ private:
}; };
compute_path_client_->async_send_goal(goal, options); compute_path_client_->async_send_goal(goal, options);
RCLCPP_INFO(
get_logger(), "dynamic route replanning through %zu remaining waypoint(s), next index=%zu",
replan_goals.size(), active_segment_next_waypoint_index_);
}
void updateActiveSegmentWaypointProgress(const geometry_msgs::msg::PoseStamped & current)
{
const auto previous_index = active_segment_next_waypoint_index_;
active_segment_next_waypoint_index_ = advanceReachedWaypointIndex(
active_segment_waypoints_, current, active_segment_next_waypoint_index_,
circle_goal_tolerance_);
if (active_segment_next_waypoint_index_ != previous_index) {
RCLCPP_INFO(
get_logger(), "route waypoint progress advanced: next index %zu -> %zu",
previous_index, active_segment_next_waypoint_index_);
}
} }
void onDynamicReplanFailed(const std::string & reason) void onDynamicReplanFailed(const std::string & reason)
@@ -1293,6 +1323,7 @@ private:
VlmCaptureMode vlm_capture_mode_{VlmCaptureMode::Stop}; VlmCaptureMode vlm_capture_mode_{VlmCaptureMode::Stop};
RouteSegment active_segment_{RouteSegment::None}; RouteSegment active_segment_{RouteSegment::None};
std::vector<geometry_msgs::msg::PoseStamped> active_segment_waypoints_; std::vector<geometry_msgs::msg::PoseStamped> active_segment_waypoints_;
std::size_t active_segment_next_waypoint_index_{0};
nav_msgs::msg::Path active_path_; nav_msgs::msg::Path active_path_;
bool vlm_capture_triggered_{false}; bool vlm_capture_triggered_{false};
std::optional<geometry_msgs::msg::PoseStamped> recovery_start_pose_; std::optional<geometry_msgs::msg::PoseStamped> recovery_start_pose_;

View File

@@ -132,6 +132,37 @@ TEST(RacingControlHelpers, DynamicReplanningStopsNearGoal)
EXPECT_FALSE(racing_control::shouldDynamicReplan(false, false, 0.6, 0.5, 1.0, 1.0)); EXPECT_FALSE(racing_control::shouldDynamicReplan(false, false, 0.6, 0.5, 1.0, 1.0));
} }
TEST(RacingControlHelpers, AdvancesNextWaypointOnlyAfterItIsReached)
{
const auto waypoints = racing_control::posesFromFlatDoubles(
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0, 0.0},
"map");
EXPECT_EQ(
racing_control::advanceReachedWaypointIndex(
waypoints, racing_control::poseFromXYYaw(0.65, 0.0, 0.0, "map"), 1, 0.30),
1U);
EXPECT_EQ(
racing_control::advanceReachedWaypointIndex(
waypoints, racing_control::poseFromXYYaw(1.05, 0.0, 0.0, "map"), 1, 0.30),
2U);
}
TEST(RacingControlHelpers, DynamicReplanningKeepsRemainingUnreachedWaypoints)
{
const auto waypoints = racing_control::posesFromFlatDoubles(
{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0, 0.0},
"map");
const auto remaining = racing_control::remainingWaypoints(waypoints, 1);
ASSERT_EQ(remaining.size(), 2U);
EXPECT_DOUBLE_EQ(remaining[0].pose.position.x, 1.0);
EXPECT_DOUBLE_EQ(remaining[1].pose.position.x, 2.0);
EXPECT_TRUE(racing_control::remainingWaypoints(waypoints, waypoints.size()).empty());
EXPECT_TRUE(racing_control::remainingWaypoints(waypoints, waypoints.size() + 1).empty());
}
TEST(RacingControlHelpers, RecoveryBackupStopsByDistanceOrTimeout) TEST(RacingControlHelpers, RecoveryBackupStopsByDistanceOrTimeout)
{ {
EXPECT_TRUE(racing_control::recoveryBackupComplete(0.04, 0.04, 0.1, 0.2)); EXPECT_TRUE(racing_control::recoveryBackupComplete(0.04, 0.04, 0.1, 0.2));