From f0d7d8dd2872a886faa956d755c1272d45f165e1 Mon Sep 17 00:00:00 2001 From: Zulfaqar Azmi <93502286+zulfaqar-azmi-t4@users.noreply.github.com> Date: Tue, 14 Jan 2025 09:08:30 +0900 Subject: [PATCH 01/61] docs(lane_change): fix broken link (#9892) Signed-off-by: Zulfaqar Azmi --- .../autoware_behavior_path_lane_change_module/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md index c5cdf0bb68bc2..b4f848e0809aa 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md @@ -1201,6 +1201,6 @@ Available information ## Limitation 1. When a lane change is canceled, the lane change module returns `ModuleStatus::FAILURE`. As the module is removed from the approved module stack (see [Failure modules](https://autowarefoundation.github.io/autoware.universe/main/planning/behavior_path_planner/autoware_behavior_path_planner/docs/behavior_path_planner_manager_design/#failure-modules)), a new instance of the lane change module is initiated. Due to this, any information stored prior to the reset is lost. For example, the `lane_change_prepare_duration` in the `TransientData` is reset to its maximum value. -2. The lane change module has no knowledge of any velocity modifications introduced to the path after it is approved. This is because other modules may add deceleration points after subscribing to the behavior path planner output, and the final velocity is managed by the [velocity smoother](https://autowarefoundation.github.io/autoware.universe/pr-9845/planning/autoware_velocity_smoother/). Since this limitation affects **CANCEL**, the lane change module mitigates it by [sampling accelerations along the approved lane change path](#checking-approved-path-safety). These sampled accelerations are used during safety checks to estimate the velocity that might occur if the ego vehicle decelerates. +2. The lane change module has no knowledge of any velocity modifications introduced to the path after it is approved. This is because other modules may add deceleration points after subscribing to the behavior path planner output, and the final velocity is managed by the [velocity smoother](https://autowarefoundation.github.io/autoware.universe/main/planning/autoware_velocity_smoother/). Since this limitation affects **CANCEL**, the lane change module mitigates it by [sampling accelerations along the approved lane change path](#checking-approved-path-safety). These sampled accelerations are used during safety checks to estimate the velocity that might occur if the ego vehicle decelerates. 3. Ideally, the abort path should account for whether its execution would affect trailing vehicles in the current lane. However, the lane change module does not evaluate such interactions or assess whether the abort path is safe. As a result, **the abort path is not guaranteed to be safe**. To minimize the risk of unsafe situations, the abort maneuver is only permitted if the ego vehicle has not yet diverged from the current lane. 4. Due to limited resources, the abort path logic is not fully optimized. The generated path may overshoot, causing the return trajectory to slightly shift toward the opposite lane. This can be dangerous, especially if the opposite lane has traffic moving in the opposite direction. Furthermore, the logic does not account for different vehicle types, which can lead to varying effects. For instance, the behavior might differ significantly between a bus and a small passenger car. From 4b11912180be2a8fadcfd42889bba54e42cc9324 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:30:45 +0900 Subject: [PATCH 02/61] =?UTF-8?q?feat:=20=20tier4=5Fdebug=5Fmsgs=20to=20au?= =?UTF-8?q?toware=5Finternal=5Fdebug=5Fmsgs=20in=20file=20contr=E2=80=A6?= =?UTF-8?q?=20(#9837)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs to autoware_internal_debug_msgs in file control/autoware_control_validator Signed-off-by: vish0012 --- .../autoware/control_validator/control_validator.hpp | 5 +++-- .../autoware_control_validator/src/control_validator.cpp | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/control/autoware_control_validator/include/autoware/control_validator/control_validator.hpp b/control/autoware_control_validator/include/autoware/control_validator/control_validator.hpp index 080e8f0e6abc3..b828c8d07ac49 100644 --- a/control/autoware_control_validator/include/autoware/control_validator/control_validator.hpp +++ b/control/autoware_control_validator/include/autoware/control_validator/control_validator.hpp @@ -25,10 +25,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -139,7 +139,8 @@ class ControlValidator : public rclcpp::Node universe_utils::InterProcessPollingSubscriber::SharedPtr sub_reference_traj_; rclcpp::Publisher::SharedPtr pub_status_; rclcpp::Publisher::SharedPtr pub_markers_; - rclcpp::Publisher::SharedPtr pub_processing_time_; + rclcpp::Publisher::SharedPtr + pub_processing_time_; // system parameters int64_t diag_error_count_threshold_ = 0; diff --git a/control/autoware_control_validator/src/control_validator.cpp b/control/autoware_control_validator/src/control_validator.cpp index 0c16fae065939..e0b9c7135e5f0 100644 --- a/control/autoware_control_validator/src/control_validator.cpp +++ b/control/autoware_control_validator/src/control_validator.cpp @@ -48,8 +48,8 @@ ControlValidator::ControlValidator(const rclcpp::NodeOptions & options) pub_markers_ = create_publisher("~/output/markers", 1); - pub_processing_time_ = - this->create_publisher("~/debug/processing_time_ms", 1); + pub_processing_time_ = this->create_publisher( + "~/debug/processing_time_ms", 1); debug_pose_publisher_ = std::make_shared(this); @@ -181,7 +181,7 @@ void ControlValidator::publish_debug_info() debug_pose_publisher_->publish(); // Publish ProcessingTime - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); pub_processing_time_->publish(processing_time_msg); From c47cd5d6a985df04f61c4499d90e6d273e0abdb2 Mon Sep 17 00:00:00 2001 From: mkquda <168697710+mkquda@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:43:58 +0900 Subject: [PATCH 03/61] feat(lane_change): append candidate path index to metric debug table (#9885) add candidate path index to metrics debug table Signed-off-by: mohammad alqudah --- .../scene.hpp | 3 +- .../structs/debug.hpp | 2 +- .../src/scene.cpp | 20 ++++--- .../src/utils/markers.cpp | 56 ++++++------------- 4 files changed, 32 insertions(+), 49 deletions(-) diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp index fe1d18ea6ea0c..a8b7a670c881b 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp @@ -135,7 +135,8 @@ class NormalLaneChange : public LaneChangeBase std::vector get_prepare_metrics() const; std::vector get_lane_changing_metrics( const PathWithLaneId & prep_segment, const LaneChangePhaseMetrics & prep_metrics, - const double shift_length, const double dist_to_reg_element) const; + const double shift_length, const double dist_to_reg_element, + lane_change::MetricsDebug & debug_metrics) const; bool get_lane_change_paths(LaneChangePaths & candidate_paths) const; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp index 1541846841f20..589f2f20ba258 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp @@ -34,7 +34,7 @@ using utils::path_safety_checker::CollisionCheckDebugMap; struct MetricsDebug { LaneChangePhaseMetrics prep_metric; - std::vector lc_metrics; + std::vector> lc_metrics; double max_prepare_length; double max_lane_changing_length; }; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp index 09a4216bf5857..88f58debb886a 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp @@ -1083,7 +1083,8 @@ std::vector NormalLaneChange::get_prepare_metrics() cons std::vector NormalLaneChange::get_lane_changing_metrics( const PathWithLaneId & prep_segment, const LaneChangePhaseMetrics & prep_metric, - const double shift_length, const double dist_to_reg_element) const + const double shift_length, const double dist_to_reg_element, + lane_change::MetricsDebug & debug_metrics) const { const auto & transient_data = common_data_ptr_->transient_data; const auto dist_lc_start_to_end_of_lanes = calculation::calc_dist_from_pose_to_terminal_end( @@ -1100,15 +1101,11 @@ std::vector NormalLaneChange::get_lane_changing_metrics( return max_length; }); + debug_metrics.max_lane_changing_length = max_lane_changing_length; const auto max_path_velocity = prep_segment.points.back().point.longitudinal_velocity_mps; - const auto lc_metrics = calculation::calc_shift_phase_metrics( + return calculation::calc_shift_phase_metrics( common_data_ptr_, shift_length, prep_metric.velocity, max_path_velocity, prep_metric.sampled_lon_accel, max_lane_changing_length); - - const auto max_prep_length = common_data_ptr_->transient_data.dist_to_terminal_start; - lane_change_debug_.lane_change_metrics.push_back( - {prep_metric, lc_metrics, max_prep_length, max_lane_changing_length}); - return lc_metrics; } bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) const @@ -1185,8 +1182,12 @@ bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) const auto shift_length = lanelet::utils::getLateralDistanceToClosestLanelet(target_lanes, lane_changing_start_pose); + lane_change_debug_.lane_change_metrics.emplace_back(); + auto & debug_metrics = lane_change_debug_.lane_change_metrics.back(); + debug_metrics.prep_metric = prep_metric; + debug_metrics.max_prepare_length = common_data_ptr_->transient_data.dist_to_terminal_start; const auto lane_changing_metrics = get_lane_changing_metrics( - prepare_segment, prep_metric, shift_length, dist_to_next_regulatory_element); + prepare_segment, prep_metric, shift_length, dist_to_next_regulatory_element, debug_metrics); // set_prepare_velocity must only be called after computing lane change metrics, as lane change // metrics rely on the prepare segment's original velocity as max_path_velocity. @@ -1194,6 +1195,8 @@ bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) prepare_segment, common_data_ptr_->get_ego_speed(), prep_metric.velocity); for (const auto & lc_metric : lane_changing_metrics) { + debug_metrics.lc_metrics.push_back({lc_metric, -1}); + const auto debug_print_lat = [&](const std::string & s) { RCLCPP_DEBUG( logger_, "%s | lc_time: %.5f | lon_acc: %.5f | lat_acc: %.5f | lc_len: %.5f", s.c_str(), @@ -1215,6 +1218,7 @@ bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) } candidate_paths.push_back(candidate_path); + debug_metrics.lc_metrics.back().second = candidate_paths.size() - 1; try { if (check_candidate_path_safety(candidate_path, target_objects)) { diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp index eb120e006a229..ef899cceea0d4 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp @@ -73,32 +73,6 @@ MarkerArray showAllValidLaneChangePath( marker.points.push_back(point.point.pose.position); } - const auto & info = lc_path.info; - auto text_marker = createDefaultMarker( - "map", current_time, ns_with_idx, ++id, visualization_msgs::msg::Marker::TEXT_VIEW_FACING, - createMarkerScale(0.1, 0.1, 0.8), colors::yellow()); - const auto prep_idx = points.size() / 4; - text_marker.pose = points.at(prep_idx).point.pose; - text_marker.pose.position.z += 2.0; - text_marker.text = fmt::format( - "vel: {vel:.3f}[m/s] | lon_acc: {lon_acc:.3f}[m/s2] | t: {time:.3f}[s] | L: {length:.3f}[m]", - fmt::arg("vel", info.velocity.prepare), - fmt::arg("lon_acc", info.longitudinal_acceleration.prepare), - fmt::arg("time", info.duration.prepare), fmt::arg("length", info.length.prepare)); - marker_array.markers.push_back(text_marker); - - const auto lc_idx = points.size() / 2; - text_marker.id = ++id; - text_marker.pose = points.at(lc_idx).point.pose; - text_marker.text = fmt::format( - "vel: {vel:.3f}[m/s] | lon_acc: {lon_acc:.3f}[m/s2] | lat_acc: {lat_acc:.3f}[m/s2] | t: " - "{time:.3f}[s] | L: {length:.3f}[m]", - fmt::arg("vel", info.velocity.lane_changing), - fmt::arg("lon_acc", info.longitudinal_acceleration.lane_changing), - fmt::arg("lat_acc", info.lateral_acceleration), fmt::arg("time", info.duration.lane_changing), - fmt::arg("length", info.length.lane_changing)); - marker_array.markers.push_back(text_marker); - marker_array.markers.push_back(marker); } return marker_array; @@ -206,26 +180,30 @@ MarkerArray ShowLaneChangeMetricsInfo( createMarkerScale(0.6, 0.6, 0.6), colors::yellow()); text_marker.pose = autoware::universe_utils::calcOffsetPose(pose, 10.0, 15.0, 0.0); - text_marker.text = fmt::format("{:<12}", "") + fmt::format("{:^18}|", "lat_accel[m/s2]") + - fmt::format("{:^18}|", "lon_accel[m/s2]") + - fmt::format("{:^17}|", "velocity[m/s]") + - fmt::format("{:^15}|", "duration[s]") + fmt::format("{:^15}|", "length[m]") + - fmt::format("{:^20}\n", "max_length_th[m]"); + text_marker.text = + fmt::format("{:<12}", "") + fmt::format("{:^18}|", "lat_accel[m/s2]") + + fmt::format("{:^18}|", "lon_accel[m/s2]") + fmt::format("{:^17}|", "velocity[m/s]") + + fmt::format("{:^15}|", "duration[s]") + fmt::format("{:^15}|", "length[m]") + + fmt::format("{:^20}|", "max_length_th[m]") + fmt::format("{:^15}\n", "path_index"); for (const auto & metrics : debug_data.lane_change_metrics) { - text_marker.text += fmt::format("{:-<170}\n", ""); + text_marker.text += fmt::format("{:-<190}\n", ""); const auto & p_m = metrics.prep_metric; text_marker.text += fmt::format("{:<17}", "prep_metrics:") + fmt::format("{:^10.3f}", p_m.lat_accel) + fmt::format("{:^21.3f}", p_m.actual_lon_accel) + fmt::format("{:^12.3f}", p_m.velocity) + fmt::format("{:^15.3f}", p_m.duration) + fmt::format("{:^15.3f}", p_m.length) + - fmt::format("{:^17.3f}\n", metrics.max_prepare_length); + fmt::format("{:^17.3f}", metrics.max_prepare_length) + fmt::format("{:^15}\n", "-"); text_marker.text += fmt::format("{:<20}\n", "lc_metrics:"); - for (const auto lc_m : metrics.lc_metrics) { - text_marker.text += - fmt::format("{:<15}", "") + fmt::format("{:^10.3f}", lc_m.lat_accel) + - fmt::format("{:^21.3f}", lc_m.actual_lon_accel) + fmt::format("{:^12.3f}", lc_m.velocity) + - fmt::format("{:^15.3f}", lc_m.duration) + fmt::format("{:^15.3f}", lc_m.length) + - fmt::format("{:^17.3f}\n", metrics.max_lane_changing_length); + for (const auto & lc_m : metrics.lc_metrics) { + const auto & metric = lc_m.first; + const auto path_index = lc_m.second < 0 ? "-" : std::to_string(lc_m.second); + text_marker.text += fmt::format("{:<15}", "") + fmt::format("{:^10.3f}", metric.lat_accel) + + fmt::format("{:^21.3f}", metric.actual_lon_accel) + + fmt::format("{:^12.3f}", metric.velocity) + + fmt::format("{:^15.3f}", metric.duration) + + fmt::format("{:^15.3f}", metric.length) + + fmt::format("{:^17.3f}", metrics.max_lane_changing_length) + + fmt::format("{:^15}\n", path_index); } } From 3c5ace825f71da53e41a67fa6c89cc316b1b3c38 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:49:39 +0900 Subject: [PATCH 04/61] =?UTF-8?q?feat:=20tier4=5Fdebug=5Fmsgs=20changed=20?= =?UTF-8?q?to=20autoware=5Finternal=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(?= =?UTF-8?q?#9859)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files evaluator/autoware_planning_evaluator Signed-off-by: vish0012 --- .../autoware/planning_evaluator/planning_evaluator_node.hpp | 5 +++-- .../src/planning_evaluator_node.cpp | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/evaluator/autoware_planning_evaluator/include/autoware/planning_evaluator/planning_evaluator_node.hpp b/evaluator/autoware_planning_evaluator/include/autoware/planning_evaluator/planning_evaluator_node.hpp index 9c268206846d9..8c0b49ce2dd26 100644 --- a/evaluator/autoware_planning_evaluator/include/autoware/planning_evaluator/planning_evaluator_node.hpp +++ b/evaluator/autoware_planning_evaluator/include/autoware/planning_evaluator/planning_evaluator_node.hpp @@ -31,8 +31,8 @@ #include "autoware_planning_msgs/msg/trajectory_point.hpp" #include "geometry_msgs/msg/accel_with_covariance_stamped.hpp" #include "nav_msgs/msg/odometry.hpp" +#include #include -#include #include #include @@ -145,7 +145,8 @@ class PlanningEvaluatorNode : public rclcpp::Node autoware::universe_utils::InterProcessPollingSubscriber accel_sub_{ this, "~/input/acceleration"}; - rclcpp::Publisher::SharedPtr processing_time_pub_; + rclcpp::Publisher::SharedPtr + processing_time_pub_; rclcpp::Publisher::SharedPtr metrics_pub_; std::shared_ptr transform_listener_{nullptr}; std::unique_ptr tf_buffer_; diff --git a/evaluator/autoware_planning_evaluator/src/planning_evaluator_node.cpp b/evaluator/autoware_planning_evaluator/src/planning_evaluator_node.cpp index 5889f15e48390..53319ffa4c1fd 100644 --- a/evaluator/autoware_planning_evaluator/src/planning_evaluator_node.cpp +++ b/evaluator/autoware_planning_evaluator/src/planning_evaluator_node.cpp @@ -59,8 +59,8 @@ PlanningEvaluatorNode::PlanningEvaluatorNode(const rclcpp::NodeOptions & node_op output_metrics_ = declare_parameter("output_metrics"); ego_frame_str_ = declare_parameter("ego_frame"); - processing_time_pub_ = - this->create_publisher("~/debug/processing_time_ms", 1); + processing_time_pub_ = this->create_publisher( + "~/debug/processing_time_ms", 1); // List of metrics to calculate and publish metrics_pub_ = create_publisher("~/metrics", 1); @@ -282,7 +282,7 @@ void PlanningEvaluatorNode::onTimer() metrics_msg_ = MetricArrayMsg{}; // Publish ProcessingTime - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); processing_time_pub_->publish(processing_time_msg); From e12bd85c41f8fa8aa1cdc67b528d39c1b3fec813 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Tue, 14 Jan 2025 12:20:54 +0900 Subject: [PATCH 05/61] =?UTF-8?q?feat:=20tier4=5Fdebug=5Fmsgs=20to=20autow?= =?UTF-8?q?are=5Finternal=5Fdebug=5Fmsgs=20in=20files=20contr=E2=80=A6=20(?= =?UTF-8?q?#9839)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs to autoware_internal_debug_msgs in files control/autoware_lane_departure_checker Signed-off-by: vish0012 From b5005b6bc117980991a5dd474924c4cb10ca7ed3 Mon Sep 17 00:00:00 2001 From: kobayu858 <129580202+kobayu858@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:44:01 +0900 Subject: [PATCH 06/61] fix(autoware_rtc_interface): fix bugprone-branch-clone (#9698) Signed-off-by: kobayu858 --- planning/autoware_rtc_interface/src/rtc_interface.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/planning/autoware_rtc_interface/src/rtc_interface.cpp b/planning/autoware_rtc_interface/src/rtc_interface.cpp index 47bc278c30564..7fcd0596b6b32 100644 --- a/planning/autoware_rtc_interface/src/rtc_interface.cpp +++ b/planning/autoware_rtc_interface/src/rtc_interface.cpp @@ -80,9 +80,7 @@ Module getModuleType(const std::string & module_name) module.type = Module::OCCLUSION_SPOT; } else if (module_name == "stop_line") { module.type = Module::NONE; - } else if (module_name == "traffic_light") { - module.type = Module::TRAFFIC_LIGHT; - } else if (module_name == "virtual_traffic_light") { + } else if (module_name == "traffic_light" || module_name == "virtual_traffic_light") { module.type = Module::TRAFFIC_LIGHT; } else if (module_name == "lane_change_left") { module.type = Module::LANE_CHANGE_LEFT; From 0715615b684e1a8b98a560ff2cd9ef03a1232783 Mon Sep 17 00:00:00 2001 From: Zulfaqar Azmi <93502286+zulfaqar-azmi-t4@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:57:42 +0900 Subject: [PATCH 07/61] feat(lane_change): using frenet planner to generate lane change path when ego near terminal (#9767) * frenet planner Signed-off-by: Zulfaqar Azmi * minor refactoring Signed-off-by: Zulfaqar Azmi * adding parameter Signed-off-by: Zulfaqar Azmi * Add diff th param Signed-off-by: Zulfaqar Azmi * limit curvature for prepare segment Signed-off-by: Zulfaqar Azmi * minor refactoring Signed-off-by: Zulfaqar Azmi * print average curvature Signed-off-by: Zulfaqar Azmi * refactor Signed-off-by: Zulfaqar Azmi * filter the path directly Signed-off-by: Zulfaqar Azmi * fix some conflicts Signed-off-by: Zulfaqar Azmi * include curvature smoothing Signed-off-by: Zulfaqar Azmi * document Signed-off-by: Zulfaqar Azmi * fix image folder Signed-off-by: Zulfaqar Azmi * image size Signed-off-by: Zulfaqar Azmi * doxygen Signed-off-by: Zulfaqar Azmi * add debug for state Signed-off-by: Zulfaqar Azmi * use sign function instead Signed-off-by: Zulfaqar Azmi * rename argument Signed-off-by: Zulfaqar Azmi * readme Signed-off-by: Zulfaqar Azmi * fix failed test due to empty value Signed-off-by: Zulfaqar Azmi * add additional note Signed-off-by: Zulfaqar Azmi * fix conflict Signed-off-by: Zulfaqar Azmi --------- Signed-off-by: Zulfaqar Azmi --- .../README.md | 58 +++ .../config/lane_change.param.yaml | 7 + .../images/terminal_branched_frenet.png | Bin 0 -> 53664 bytes .../images/terminal_branched_path_shifter.png | Bin 0 -> 59599 bytes .../images/terminal_curved_frenet.png | Bin 0 -> 76194 bytes .../images/terminal_curved_path_shifter.png | Bin 0 -> 71940 bytes .../images/terminal_straight_frenet.png | Bin 0 -> 29125 bytes .../images/terminal_straight_path_shifter.png | Bin 0 -> 24433 bytes .../scene.hpp | 12 + .../structs/data.hpp | 1 + .../structs/debug.hpp | 15 + .../structs/parameters.hpp | 9 + .../structs/path.hpp | 37 +- .../utils/path.hpp | 62 ++- .../utils/utils.hpp | 46 +- .../package.xml | 1 + .../src/manager.cpp | 18 + .../src/scene.cpp | 100 +++- .../src/utils/markers.cpp | 119 +++-- .../src/utils/path.cpp | 471 +++++++++++++++++- .../src/utils/utils.cpp | 80 ++- .../src/frenet_planner/frenet_planner.cpp | 9 + 22 files changed, 991 insertions(+), 54 deletions(-) create mode 100644 planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_branched_frenet.png create mode 100644 planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_branched_path_shifter.png create mode 100644 planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_curved_frenet.png create mode 100644 planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_curved_path_shifter.png create mode 100644 planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_straight_frenet.png create mode 100644 planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_straight_path_shifter.png diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md index b4f848e0809aa..ee371f8592833 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md @@ -787,6 +787,51 @@ Depending on the space configuration around the Ego vehicle, it is possible that Additionally if terminal path feature is enabled and path is computed, stop point placement can be configured to be at the edge of the current lane instead of at the `terminal_start` position, as indicated by the dashed red line in the image above. +## Generating Path Using Frenet Planner + +!!! warning + + Generating path using Frenet planner applies only when ego is near terminal start + +If the ego vehicle is far from the terminal, the lane change module defaults to using the [path shifter](https://autowarefoundation.github.io/autoware.universe/main/planning/behavior_path_planner/autoware_behavior_path_planner_common/docs/behavior_path_planner_path_generation_design/). This ensures that the lane change is completed while the target lane remains a neighbor of the current lane. However, this approach may result in high curvature paths near the terminal, potentially causing long vehicles to deviate from the lane. + +To address this, the lane change module provides an option to choose between the path shifter and the [Frenet planner](https://autowarefoundation.github.io/autoware.universe/main/planning/sampling_based_planner/autoware_frenet_planner/). The Frenet planner allows for some flexibility in the lane change endpoint, extending the lane changing end point slightly beyond the current lane's neighbors. + +The following table provides comparisons between the planners + +
+ + + + + + + + + + + + + + + + + +
With Path ShifterWith Frenet Planner
Path shifter result at straight laneletsFrenet planner result at straight lanelets
Path shifter result at branching laneletsFrenet planner result at branching lanelets
Path shifter result at curved laneletsFrenet planner result at curved lanelets
+
+ +!!! note + + The planner can be enabled or disabled using the `frenet.enable` flag. + +!!! note + + Since only a segment of the target lane is used as input to generate the lane change path, the end pose of the lane change segment may not smoothly connect to the target lane centerline. To address this, increase the value of `frenet.th_curvature_smoothing` to improve the smoothness. + +!!! note + + The yaw difference threshold (`frenet.th_yaw_diff`) limits the maximum curvature difference between the end of the prepare segment and the lane change segment. This threshold might prevent the generation of a lane change path when the lane curvature is high. In such cases, you can increase the frenet.th_yaw_diff value. However, note that if the prepare path was initially shifted by other modules, the resultant steering may not be continuous. + ## Aborting a Previously Approved Lane Change Once the lane change path is approved, there are several situations where we may need to abort the maneuver. The abort process is triggered when any of the following conditions is met @@ -1008,6 +1053,7 @@ The following parameters are configurable in [lane_change.param.yaml](https://gi | `trajectory.max_longitudinal_acc` | [m/s2] | double | maximum longitudinal acceleration for lane change | 1.0 | | `trajectory.min_longitudinal_acc` | [m/s2] | double | maximum longitudinal deceleration for lane change | -1.0 | | `trajectory.lane_changing_decel_factor` | [-] | double | longitudinal deceleration factor during lane changing phase | 0.5 | +| `trajectory.th_prepare_curvature` | [-] | double | If the maximum curvature of the prepare segment exceeds the threshold, the prepare segment is invalid. | 0.03 | | `min_length_for_turn_signal_activation` | [m] | double | Turn signal will be activated if the ego vehicle approaches to this length from minimum lane change length | 10.0 | | `lateral_acceleration.velocity` | [m/s] | double | Reference velocity for lateral acceleration calculation (look up table) | [0.0, 4.0, 10.0] | | `lateral_acceleration.min_values` | [m/s2] | double | Min lateral acceleration values corresponding to velocity (look up table) | [0.4, 0.4, 0.4] | @@ -1057,6 +1103,18 @@ The following parameters are used to configure terminal lane change path feature | `terminal_path.disable_near_goal` | [-] | bool | Flag to disable terminal path feature if ego is near goal | true | | `terminal_path.stop_at_boundary` | [-] | bool | If true, ego will stop at current lane boundary instead of middle of lane | false | +### Generating Lane Changing Path using Frenet Planner + +!!! warning + + Only applicable when ego is near terminal start + +| Name | Unit | Type | Description | Default value | +| :------------------------------ | ----- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| `frenet.enable` | [-] | bool | Flag to enable/disable frenet planner when ego is near terminal start. | true | +| `frenet.th_yaw_diff` | [deg] | double | If the yaw diff between of the prepare segment's end and lane changing segment's start exceed the threshold , the lane changing segment is invalid. | 10.0 | +| `frenet.th_curvature_smoothing` | [-] | double | Filters and appends target path points with curvature below the threshold to candidate path. | 0.1 | + ### Collision checks #### Target Objects diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml index 91b296f8bd40f..df9491576a4ee 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml @@ -29,6 +29,7 @@ lon_acc_sampling_num: 5 lat_acc_sampling_num: 3 lane_changing_decel_factor: 0.5 + th_prepare_curvature: 0.03 # [/] # delay lane change delay_lane_change: @@ -37,6 +38,12 @@ min_road_shoulder_width: 0.5 # [m] th_parked_vehicle_shift_ratio: 0.6 + # trajectory generation near terminal using frenet planner + frenet: + enable: true + th_yaw_diff: 10.0 # [deg] + th_curvature_smoothing: 0.1 # [/] + # safety check safety_check: allow_loose_check_for_cancel: true diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_branched_frenet.png b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_branched_frenet.png new file mode 100644 index 0000000000000000000000000000000000000000..51f3a2fc46500039d3a136d93a7918b2de82cc36 GIT binary patch literal 53664 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 Y3kY*Xz9Xxr8vp;8S$x@Qq=RsK8%D5cvv0 zAUcqWyo`?b*ZoC97t6UU=8L1R@Ab<~+?FqkO8In|(p1^frW0K?xGB7pM&G`Qx?gh% zr{>KDM=i6=R|VGRh#!7(5#Ik~=M~=qlbFc1^YQ(_Z?7_?Tgv1xG&npck*QX>g1F+e zb+w8}Cmq@=n+*DOR2;$R;(FB8mZ5yy5_FfuN+W77E&qRGl1XGA0T2IwV|=OGJTv)})ayPsDd(n}fRt&CH0$;%&I2cN zoWeYjN4#gid-LyOIcc8Mav=rn?mR@@l&1I$n*y_MR3CXfxf%9rDbmfIm7iO!7PuiL z&tPwptbj=eD;q)i`29jZ{^tq&vHz5euQdvtAc?<_(yIqlj(-q@l^*r3?3dg>y+_;H zoH+A6&9AI1Nto8SNSFX7_1E->MGlmz%cBIYAGNuhv0s<|%dX6QU`~zLti>-5ENAqJB!}#HO>mMeT#b z_j3^YjO-kptV@Y7t9*%IVyP#?&&azX;$lrh|BSpd75hFRZy{DYlF^Rpy0`fER^L>^ z+414_YG>kakigzD0$Q5?%`C!2y~nja?|61~O4pXP%(^%4#Ds4sonrHk>1w}X#7-x~ z4z0}=9OnL(mRz(#h0L-Ij8HmxCffj%Cy;--yS{&3)BSTo1@ zQdK^0yUC<6#qxki{YS&l(k&=KN^Uu*V=Ic~jxgOe%n4~mUH5AkSmx4qrP;LR)7}X_ z4hRic9c1qMo$r{JT4ydk$&oprsva7oA1P9p=(*eWz7?rr=LX_65R~@huZojAW#lkj zzW$n!0#r&#=){oH2wDe3Zx$z3B{(|kb+j$*;Fg#fe_3P}QlC@k!ad0(4beG>|H}!! z0&h1f#V>o91xk*#vb>fvOr2oj%JkRYwzc(H@L z*?&oCHenA-rr!o_yr1izxq0B!FEcQuUYyBoiw~kE9M2wmF2BgOzOaM$QRW$7=>yIz zseUPOJLN4O>4w{3w{6rnR+#%aW1iffvdk7w9|}@%^z<8-gJ!jN1}d%))<8lifVj*_maT>gE^wS<1d0O|kLWs-it6V*XPe9pF~qmY zWXr?$z_hYF;zyW$!k9sN2)6aIH#aOy(I&FOVM(G^{9bsn*7sWt3ZRh5Up#XC z?zcUe*KHa0!#_->dkpAd=ch8shp^1+q6C;!Fmd)TV<}sI+8J5+)p6$Ez22I<_?=uk z9CL$v6~8xapUG`2Og17?7D>Y`;0F8O?rB1~s`Om`j{SDF={OqDGQU3j9d3T_ru0s{ zZTO~{`r0v`ajA7KXpzVCr)|CR_uR>)8|A{SgNhS^@rQ5a2bYQqINyyLb55w5oQ_Bz zNmMto)Aj9nMq9KK@GnlDmxYn>9V*O&po;<3jx$T_TW)9t8nzO`*0!x))i)^@DK|bQ zOD_`!zT05QpgqHS#=%iU+TKj-l`X()N_9c@13Kkc){}pJ(O+1IB0ym%ia#EbGV0ZS zHNMd3nmip9-(sgJW7$zi;Y7Ss@^h1@HgjninJ7*~UMrp_77v-8t?N*ykByj~TpNWe z0ou02;$AmKX6_c7g%@2i!}L=`JOyEal4 zCZGIV_oh9tAOe{;d~H`TG%=d9x5$5E0V8pQ$qJ@Gzs)C{y@(ZILG~zqQ?y-;*m};% zMn-Y;)z=oQu*>zmZF%4g8Z|BL3|i2AX%L6QWPJC4V?Sm@<$N$zxKNlS3T--5ltlapdFQ9U=Y>q~mSl_VwVo5E zmK_91iALm=M;FSJp?S~6k0xg-s-Imqzn&WY>iFrVCIx{;4!&5oIOaVmV1|W&)4xnI z`6cVKQgNaT{GlIEMH8)3ihzVz<3U>dF2aaS0F?xP^Ui&uC2m`6C{)mt)xBYXRkwdX zRajk7%)qI~1BJ_M>GygFMsN>alHzZtaBum03PphzT8%#fM*GLSFZVCUn)LTAU$%rG z%smWPijz4K^WBt(1)5*+mfS}TxIbD%D;31k(i9*3m2J|5J1v_nU7uOD32>`54$6k84`i5jhI)k=S&M3II4`SB=?%~3Ks z;xaQjqIPNuN_G<9tY`BYEFrR+UDDD_+(!X>s`Vt5^$z^Qqo6gP(+-o)ED_3L zA;;kgA_b8#dsQ#X!nL}1GCh$->mK&qx91#)t?SMaSgT1w4|SBANs$yqKap`NMqjqhn^^*Htz9*EqZgjm;5GiMSm)t-#a-u={E`qq_rP;Z=_{V zR*A$F5lG%_!y#3-S(j4#_9Cc5NZo@o_X8eO92}hVIp<1i!l)LZchzXTYrZ?As{FR) z7)2JaUo)L_3oTu4?{j_e>M;|%h5~U@$SINpBY(A6vM>klLPOJKI1j>$HZ~H6h)x}X zVsIJC7Y>eV3?-teBAvoicNb6K14gFLyxyC=Fjzu3AJm_51sx}hnAT=c9KDXU;KQC! z&k6c9<$Uj1lUlstpjbs{zQ#tA8y}>U1yoyCiGv@2K?nk z(#~hbN=I|-Xlo{i(qV~R)Xj56{_=b2a)$~se;%!+Voxh3#@~y8jo;I6CN{B>7PAz})lYB+Nnf5hhzX(|w*4nV`J=cWGK?6@_-pNuf5HmWL zueqlef1E6Dubf_1U)2RIp80u2LMMOet=gaQni!cLibNj>c~g7ls>)BIhixF3^E5Yx zTOfmwM6AQ^ydnNK_5)UIzu3xc_sYh?uuj+BUdBL@uPvn?%yupxF7rm$gTEVtc6Hrh zpZ;!LVFQZ60PzeLAZ#C)U?na~dz=yt_7#Xf+OkI8Q;-=hRXV3A4zX&q&rneWiG4=O zUUsVS8yuRUp#e z&b~q7fjC<90V87i9XbSR*zaJ3Cx@e|;#d*hf%?#A8kUY*6cAmbRgB z#`gg-;E6PFfay5i+PD^TO3yOx>c5D3M;oV;5Lf%y3Ja40cf}%YC;7!(ogV3j*49#-&#s#P?ZO_-X zN(q=!(EP;-79_^Dm|7|jYh@2Dp?c8?-zqKeXw=gqtY_j)AA8Sw+v?=^6iz99rw1f? zI130Ah0sdmQOO}per~2K6rD8UdH!Kius*TH)Kdwm*rUv}-|d+kG(75=9-$|w$c(Ar!MA&-jl20`;oiStf1v|MxR%Odp}NsM4R>ab&+ab% za#OCJ<_BOszCJ0VOdsNW<+7$QuL}gQTOUIF2Hv+;>OD0x-Rnml_@6y%ZDgkyL@#fV zKnp0UUX3pbB`nuV31bvNJ!SU=G^Ph$jc*=YRSO1;3~qZPKL>ma3`kdxES9`I(d?H; zi)%PWJbPG=ECrY*1H~&pzPw!~1J3d?N0i`S^YS9UK4eT(!O!(5taAN3;G&H{)HeRE zT0a3L{k@1Je~^N}@J9cP7UgolY<_9Q6NJRUz#z&>M)Ab?$8!xIeMn{O>nxz4?V++N zC)X|Qo1(k%N~{P)7#$l;spJR#(0+ct?g3`-VAA%jJy z<)H)AGAv!Y$%CmCN1go$kTW;(JFEfVT^Be|JVs!v5Ry)N-TcM+tl)-a7uS{$Ga-ww zk}V+D5fG?#N-FdRF{oG_0TerBcNKKn0dc^3BK^QpCP;u_wBCO4z1kbR2L>KYt`n`Zpu2*gD7jW?13tQMHNx4cla8{FAWIZap%& zT9|IxePk(?)<5~9qqQv+0*yXLmsD<<`xM_69=@X;&)RGKmf`U@@TSgjY zLFT)U5tcA;51y(jqY>fsbj#EA zwXkJ{6BCp)aysh`N1G>X=#W{Co(fj~q_M14L;EQ5k@^D9=##6n7c_--*i-HIqKomz zFQHxY;p{i_?}qMAytwP%WEh}B7t#$XFL=8J_Y7@2XinaG(Cr<~Okt90agdy>&%KCG zBF0z154BI$qY%UC=8-2-FfcIoF7-$b}wrK3G#ez{fh7@81lfMNcnUf@2@1YxkWExa;3VS@^$ zPTTQ$$$BQx$Pb`v zLFM|$Y4qU_?y%ZvUxspI<&R_xf*`C=H)2^;4leFI0u)VISrMoC3kLl%6%r6ub?uK( z6Tzqn7WI{16UBHI;bk+G2(l{=1yLnBWyz)QH6866eq%jVIc%$h$w!a`S^gG`YyI5% zR~r6c!Ng5XeL)7)H);v#65;)$rVK0Wlqz_T?K20=xvTd2ABZmvl|L4`esP;9H5+vU zff&?-m3tV`YoSqJ59r4!GSyJEDs^r_+J0VV4L4I?P30+fHf5E zX8_j2W9G$kc$bFs9P1-v0>KdDF`g0~wqU&E^zQwAj?)P7c;4tz1ou>Pf%1Gu2c0#LF5xpumZqR1 zO#huJ?$rvR_QXr6JCH`Uq(WsfTJh%pe0H%@k4)ZAO-Q#XBr$|Fgb&e))3%|npG~(o z{nkiT0MW4Q`Fcgls*%Z#wLdF8{l{tWS*Brs-3>0Huv3!E^C@t&^X!fSM<%hdeNqDi zGr!qakk|Y3uz4IED;8X%l)IaLZXK4xLZ5KNT&#ek#$@l`e1`!=+>^Lmd zer#&acuJqW#+Np!pu?KbBasDjC=urhTC+#<8k>f0`6g@Ap3P}4&|U#F&RuV3|sIm5Jbt}1?$g;jrNn9Fztg23syxCNvJaSx4exqu@(O8d{)ThN zUfk)0>T_k-+~0@%t=x7DB%})LLOj56*j~J^X8GeO{$bqZ4Qb_`pphEuKxCpod~t3O zVxhba`id&{bF6q3yd5%xx2!|5Z|5`(Dd&1$!mPjumVW}if~Cojl$76{`N)rH_IG~% z3IDZARjcu4z0T*WL;wXYjRf*ENT(PN( zcE@_oSSXmREhErvj1KdlSD62uTbkdXIYHKxhy*7C7wVRyqB1ylO(M?NQ&}jWX{yrW zq6JnQ$XXs8$gV+Z;qDxUqi7s4j4HVek(J6irMhJ3@`H4-rDF}TFwKE#&K4$C^}qe7 z7->AVQYR*yz!gCKf|=r^D0^0g`IM15YZ2XAMcA;>dki8IwEj=n2YkC&(`<=fI-DC9 z=07P6=}*!$&I!^P<-`UDf860rJn9;?vLL{QyKwJAFOmk+$s@9&Tix=Y;xR8~mz=8zDi*`Tq~G$Fs)U!je0VMR(S&A*eJEL#;gm7E ze0a4rUD)eT{5P#=h#8k;F993a-fH&T^q5m(HHlORJDXhe2?GH`ONfkPB2hIIk9m4* z3eQypySm)SJH7l{N`}=NT;_O$0*e-|RKeg>JXyM&k)B?3Iu0_(N)rypa!3)8;}B|n zr1rE?L#2vKzVO^^U<=O-Nhv-SQVCNsswgM^D?eByJ|7g@&TuRya+*SgNUmThw2LnK z8Qu5Bm&wtu5I>N0GFDSHKa+8Lp_?;@4O&Bv22zI%I?Bx1iZ6|O{zUbhZ7y^fQfS6B zZDh(X)KL;u;neSdtuLkng4GIyr>jEMBQq+Cb{>Tqr=Yzzw-MW9fzz?6c5Zic>Q$a==I2jsNw1qU2cfjc?v_b9uRR^RWL~ABi$eTkHVqT zs2^gI$*^^QcK*I5lX4}p#Btf`BE^$6FVdFzULQ+%NcJs9V|90`OcNJzJ#iMSHg@6z zf`r;c{sz34Uw*nft}^}Q(hb6-#-n+ZlAQdcy_;L@nXEh-ILwLyY-Ug$iu~g2{aBh& zS+tSuW*?%$215?55?Q1s6luBEBFRs>!d^#)-}iuxzd=%&pmVajyGidm6+${hrnv%w zrME?r>?+QoaCYpEE31rLL=1!r;Y6gNT5~Z$`3eSdX$n>Q1mVOFWC_Bmcnb9C85#JP zNJAcYk@WejvH~UDT<pavjA*iZHCjM_1|ytk?-NBR085mqTDBddV= zL4CS=&^P^4Z*Tz}2g*=w@^<0)UXu@H8}dLKfi1R{!hmpdol8nUjYTu#5*bew%zswr zddWZ@%)d1_^)Bwf5Hwii-n`4kfLX1ErO%Al&_0+Rj)8Z}kYMiEq$39Kr)M7hLxefS(Ob#|!) zm9qBRa;KYNCW~DouXhX!!aWvBQN(_-DnsUK~%$WLupUC)u3xInd`H$ z>^ME>f~i0Zv^B_l9(h}KGW&Io?&f*+&xRbM!!k4e67J$cBmIWfLvOIOGD>bBJt$e0 zVG^AorIQ3BC4zUDdst2xVaUtX%da#F`G36tH@s9s-T1xL-NdQocuNtMV6{D7a>kVR zjgD1aY&QS!DR8Np094o^f4s@O;(n@9#+@Mk&K3zP)RUmpEwzj0U`qWM%#_E8p676Y zPsPt%Qx;VusyfEiJ*DNPTk7!LeExU$r~0C&lTFZ5OB6rNqb=KuTA71dp+zNagwe08 zT$Ed{m{0hwE>m&4xKQnu!;dBvUO#88`n=4w<)hmK-dydpk-WQc1m#YlR?z3jPZa4^ z1>>f&{JKJzbdwFaf~bhpmJK9#_F1`9kVWRaoZU5DLg;>?DiIx@gN3Vv@KQOS@6ZJ) ztm50@=819ruWk7sg7Hk|snS^3)be=A;4-GB2#$9Z4RIeUDrEGA>{d#}i))VR$9YgS zDe zjYz?%dw%CmWY}z#m{xOm+A<=Z5E#KX3K>I^LM!0MM|nBc%q27=JHu$ET&vHV_6W1& zv@yu__+zScs{C*5lB1DT9kmS0;0=zt&iE9KEk1E3b#JQeF{f-ZK5!w`AHo`lMF+b} zaquVmEnztI>gLlZ%l8|N4d%C&2(9g&WvOlz8_EY;oHKvy;7CqWHKy=dd0K=zf$T8U zY39wdKW9UOTlkIQN7K9Sw2om5p9RClfr{HF#*m^vapZaGcss~?74{+}dNmXk(irGK z7)k+GBg>1(2-hJWx#R0j97JShH5#V9VE+mr=#sfsshGDOz5oRU2mlTl$LmKuM0s_T z7imoES%|^)5n;Tj(5wr7C-nC_vr4w1{vW~R_wV_P9j#Hw>gJ#vHP;SqGYR> zKab$ytFBiyR+yDGc@u%fzQY(~fu&?{>@SoB;u$wkEe#d~=Ywlha^J+rD>az@#FwRh zMns`fgf;UU>Zl)Gfpp?j3c3CMvmsm+#>T%m{gRQbC>-BfuBnysrc~OL_6p|*i~GdQ z4SEK`B->xz0lYS26{=#mJq4^ZQBwyayIPZ#M5|JdUY9}|sdHk^jw(|)JXT#(ldJS( z8+qu9o&M@@^}ogp#i=<$mXqVTi6?4nyAAAmIlnx?%?IWBEd`s2S6+@CWM#YbX5*bC>$tsA?iQ-dV9dJdKwO3KLwDvf;r!~+QlFEYk-ux02m2oV! zI&DWl=^~uMJIkJ+;K${8MFmx$>=Qi}*RC28*Z%OMT z(Y18!`H%?$Q1QUba{LVFtg$Vb3I@7i;=A}DFAG8LAHI7UN3<9o|A1zX93|!BiB48S zu)#=0MB&Mr+K9?>U97Pdu${ud3aoCP@`iAp=zMUDy0JyLMK~)KemH)9uQbf9=Y1^% z?I2vHfe8y0G&DcUmFMFoJ7oXpuroDJGkFb-D_>|@{I2?a!^W6Z{#(mR3k{c0q7&HhFq zZIU|aeAqQJ&O(9|P|cq{l6==3=_Gm-x;NUY?>I=)EiJ{xBEP%%z$}*>{_PuZb2^T6 zRo3;hEK)|%U;ryaS-)!n+_T56;El8dC@z1a5>aZ=gdX;7L%P8z61SmTLvW2t4d17!sq7i!OWXYD(TGlm7iX-r z*`0&l2rZ;6&Srq~go0%7_z|r}&na{VJ2#0}_rk26BM*wo$_O-sxpG9)z3D#}H^@dZ zOt3(mxbQKXWphk#+=}F90|0@M^E`FWwFPeIQ;h~7UNFAHEzJr&%DlG{)d>Y)0438~ z#D_qf)f%TSD66P07EH=htjPC=FKOKDeL1ED3mS#=#ibf zG9mUC%Dj>Id^q+hpIsHGTQJt@owN<*8x=V;>JAt5QgW|MoOEjrXgbG@V^jA_f250H zP~+z0|J`yP;ug^M#rZv_Y*o~Go(i5_LVPt)4y(EIhi>pHI`qmQr+JxolXb5S1&Ezj z8`5&u<^$2#7P-XcGWZ245SeHt>-4u+f##-pp-=o{(DHtS+H5rahR9U)XFRaE_Lhoa zqhp8ahcE3)3=vfF*g$QR(aq*~h6jMWf0=6^)qH64Y9wNbf-=-r` zG?m#C>oT!SW*q95 zs&nFzw@kqX>SaTQ@#0^JHrh6o7z3p@rhk2%5on#^y1(^c3AIKYs)uL^ zAm3>zr_b~!gI_!NS%56e>rs*EhK}S|-$)wRc-E!lR+&`IA zXDN*KsZ9@H{8?%mdijz^@tF$$DO@Q;X;ky~jYPztSOI>~YqT#BLzS=xG71n0k@=bt zuJgEoMq_GiGNbDdBP3yp!wz9ZTzWdQcH^ z{2XI+rT!ddNc@pytEN0}Mi`6Zu+HYHHD<7Nbt~a?@6)m`cHJ{ z{RsVw>U;Yq<#Xmu9~UBy`LRb35=Nb5>6;EL2OLl~iJgNV2h1MH4_`^p+|el|YbES} zCUVepDolnqPHvjxt`?8(nX^aQIy-JoI(oRBmUjdE6&uyalq$kYG)|j5v5*Lz4Jv8a zkb*gH7c-7In zJ}Vq}b1{0t{qPreLUp%@sgtJL@dMhhb--tG{-=V&0c{iu^Z%hF7}R)V*gP{*5sW@i z`{CT*I}!G2yPQ%>AXwt>G=71Sbf+GPn<;AhUf0KaZKpi02L!w-mMkiyyu8xEXHF&QXPqtGV!*E$?dK83MU9mJ8;%pXx?QGf}(s#=D zaBcSBI+|20kRUmN^%=*Yx}hL?3fD%26*fv#X~lU~uj^l->;vlXvaKq3T&7JxQrtX@!xmMTp6*{o z20tNjGq+j$d#(wWC2*ND@uDul>M8HkKs_GKOIjs9sGCo2rkqaQa_D!1%*2C2xxeKU zdST^OG(6K8^2G`+oUSub;>Baykx!*orgw4N$76OwK^u|eyYol*Bh`| zl>ancmUrj5ZpU4|Q*RXTr9cs#8^sQOUv#Sit#s8@aJ=nh>9O zCStzqq!UM)Db`+XA7WR6XM5K_n`j)So z6YBI-cr1>qR4AkOjkqrBqAggu|2+9bya|fLL>xa3 zPyyf=<_kwUz&;Hp(Z@dnkW8ZluK$ce|2d4dr8?Hlqk2GHIi`H8AbA9+%a=`ItO+a9 ze+h#a8eo?h7^>ws{~k5x_@eZ+mo-hl+Nh#lJZRK4*)`xQ5wnOWp0@;5w_InaBpiXm zYE?53%g~}g`@1>RMD~3x2go}+iY|s{)#k(KmR8NgiUH-staBQxd_EyygL>hZ(44-^ zUj?jJhD3K*l~iI#pigg1<-ga4%3m&NWc_Gt&u^9_rz^|+51h2snJjzqK4mdM$rz!^ zh0cuMZ@NxmdRVR9l-)z;iWK~B)+Lu7?nsuJ&s1It8w_urOrPtYv@BnH_}^SfJ{*Wi z^~d%3_}^}D!yWXURy19yR8=|3IaViFE>E^P?kE>>0%PeggdBqy^n3NW+QNmnIzrzo zY0w?n;IZsn9H~ikw|Gf)jY{3(#Y~G4aM3TBE5z+<6g$%ff4 z2VJa72A*6id2jt5;2gaLC$4xMi(T2Q<*YtbNe$dzO3HlK=|10^Il1J@8t~2oGcl3q zr=RSk++JOF+}XhbstS9{NGsPy9L&0>QnoaQH}S&h55@h$X#?)KXw;10 zdU{A-Uu8%=1f5)L(KeJ@itBeekXEfe>7={n^-mviM$xW2H*~KYseUmp$*xi7plH^_ zTT#!08)|mr)rKMN)!XGO;#9qile(nkp2>a8yG^0?s5&K$mBW;%tNX{}0RwEdtIZ*^ ze%$tR2k#o;D5>i{vsES9wh4ozR78D^tO4U0v%Zl!eI7&Bd;(N&o_j2*`@a&ck9{`6 zf`Q=2gUcXNEuz(^jw|%+Hi?`>OgnZgBmh49}?{*3NVO>FwdyizxKTg?dE77D^Du#qkHj5}h!H?HbLD50?7iPIS7Q_cm zr5dOuNu=a_PZ1aZw8}tRJB(l(EP~Y@5NadVe1XDb7e`97<|_jKfhSG#G@5jG@A5I9Da2cy zdBacHn_T`fKFmlxcDOq4@|HFPPkh7xG|}VS`oL)-=7Xa>$e-+g0j@kSujPrH;WFvj zfZH4o&b_=U=(xrlP9;Gl;lc#Bx*ZY(o=*v#oMy&pYFl{v;CGos`!mN85-Pc@vlBMC zZW26fS3OcqVAe&iO}hxIzHJS>wrYZgVGgLjb!ra3PGh3tO0?wA?|d@AT+hHs$6bq5 zZ$ajBWG!Tn3xraL+oaDq;J~lRWnX8n-Af#JH+)auc@6My;ec({z^kRvYHd!Ti-2%2 z21eq>N_PZiHH2~?iFRP}kGQqIYC^!{)DSoPZk&+vqRn#d>YyqJ*Q~`2X`mmMK3dlQ z;V(U#3^Cy~!^4D7dl<|6iBG0qqf!a_KcxrjgF_sOf5T_m@333_Hwiet^K@u;w|!@+ z=EO|7W^l@G34PgMdC4O6_)=|T^ul!?dH%c_02s0$Xsyf6x?!u^0|r-?IOcO?$Dz=V z`6sr|k;7+abMExbZc*EP?ghSzxKZ(RZfVd0Y3Rdc-PM$SM~MEYSx*$MWR$}kxS)D^ zg4`j%4l9|FVgQG_A2;xz@%TWfBj!4d;7~j${w;G9+%oF8=tYL>+dI66zN822htm`< zJb8q`>lMLxgm&KtQ6Qm+n|?+o1cHVWbRXWCX@f}pV6V#c4>4D>VazE1%wpTm~A0K|->UTuA@WnTtF4o+bL|vV# zYcIpB|79_^^z#T@+NCad<`x*viaq6yh!pm$4_!Dt0Z``EMB^jHiy{=;f)B0%3*uhn z&ToQ0e&AjMluY83-4;(;NK|NftgAlI~1)^~1KXJ+bO;Z3VhH9q5&=h3nP%E>dlWt zp{m8+YfF}s-3SK*lQ&&zb~Li!cq`1ShrQ+g^VeG^?+#Ix+HTPgC4%DZ$(&{{(`#M! zR;k7Pd3D9+QPKZQQz`W`C(n`(kB-6@y_Wl;&XP3$An;WtQQC0Bzi=1bK5RC#8yFaN z*Iko)L&JbjzV;O3Ci4oK&i3&GU2jQfMkSTX35obb7KHu2li1Ui>26h`44nsDmQ}UK zaA$SI_N7??8nRpnyunMW#$aNK%@j8k4L~sK@FjFM2}DV<$$^tLI2I?$Jk2Mk(lPLQ!CVnwr#ipz2Ct%JGA?MN&u_}2C=1KWNT(vSnk7~>wUR5{%re7k*^%zFmJJu+)m%%4^Rf07$7 zasco@`jXxIbRAvt{_ksl?ac1-N?D8;d$N_kc?|)NOQbogb9Y#7fv7^iP5WbFdJNdA z)-o<7`;sIBNndWH{cXk!x!xd{d=+uDIBOU$3XlI_=j9IkeYGEUxk{@5~aUPK`byYa?4%@iM;Vmp)!h^B3O6x3rY z8=I$#?RgbuHBfsDxEZ{O1ZlEKgfS40*C=-I`J=?A0Wa*(?ByDybF(Fp7u@ zldslKNWC8)Y@U8|b}@rE^z}~sU2*DOV&ciJZO<}_4=h%5y<~fed$@E#`8YR6d zcwZZJ_GH>5Yro}_LT$WQNJ~xDUQ1EBw7-2Yg#}18@Wf?mZv{w6NF<=)($K|DBL+eE zHyv(GrOn0lZTD}>GrEAVWnoML9OpjL2@Q%ozT`-#S24}%beNdI_f#PrtgSmN(~iG< zZrMpu+~1CW!MTlOt>`2?lWel#&XRt#t{+$a#Jms|6-1x=#-t#{kfQFiCBj9L{?hyM zVt}=ROX$X>aWCqP4LjzHhMDy5p_QElOdzYuyex54JD3d$#4I|+s5cb)kgdWk4*p;& z{V6jC$W<3MCE>c;^M!u%WE}c~S1aSxIt6%^bK)3*o^+#GieZwb;gY8EcZ-tOKUGF!q24J4n=Yior-I2H5ti7rYSO^F+o^%dL zqfIniRAMN`hEI=G8y3KlU;0#@X!YAH0C@AJkMw9yN0#oGHUptr@7?tH({|K6-Z?|Aio^ofSLIQmTl z;F9U|+_ZaH{7MLbvRecf6)|yeazdK8D+jadb+$llUK?`oTT3Z_^t?EY+)>Dola7%V+!%xC#X1i>q--&o_xkfHnh1af-@-7aL~T5 z^s$f-MKUvU_l8&X`PZ+)h%->$me%MULEXuiX#*3(ewL)8)sf*0!38rZJsC3dKv#r1 z%=dUAxak?r9E5wwMW=jgj3EwlF69@*ll7N1R;W)vbtQp#?(9qSMb1-CJw$FD=)<3Y z`m`t6S5zG;-s>J?fQ6w6U$!b&c7N3gi}(=1=fwSIB0gehgRd&1T663;mVdih5l`_r z`sE%}|w<7=>1Pjfz3!#AjJ3aK^OJdgNwN5=8}xFW-}N1w}dndiGjmNrH^Tp%&arUeN* zz04w5RTJ{na<75iL{Bz9`Iqdkzq1(*gxZy){q)(t+oUJ?Gqc+c5#^e-Wq_}*jMejw z9F@8}&KE6mw}elq3mE4~q{Oxzc83`YxKG77R{`XO1md#$+SG0!RQ0ImPAK(JDw?@Y|w zQa>xmv7d&A*bbKkhp@&7VK?lJS_E(zRGBAwAl9|(%HF#|vW1e>X}k)B6PJC@^j)s6 z$cgG;bC)OS5Zd_zj_2=;=&?hDWAL5b_VXE?C=p-M10F>8XLqk}Y6B|M@jasLMMLb$ zO<`gifvn>VRgbVNnZlRDy;pj(CD}Hf6;;B377;Fh$7;SC?e2AFr1bo9vOeG%MdrR8w? zcImHBq*DWo9raty(V@CTKai{523lFNCzqHg5Xc|*Ph8-=#;hxG(xzT4^JRig{}`WX z%AEKHQ4X4>b?H27ZFtdsk#H~@4M!#)jhHPA&Wfggfsda+AaIM!>Tb#<89*Gy?hG`| z&bN@fEPBPh+xYptyVUdl^#b@i1HJVVP-GP>DZWn7@*iq|&ySRu$?~QQ0IXo(@v>|5 zWT|abP{-L9+G54z+VPQ5rr9XMLF5Uv;R0+kWo{>=940_8gOj5;ea=H!zH&1BUPsQ!=f6{DZVhtgxlMp%sqos9#XPd z;>pw3PgkdfLK=c%^tAJme+l|pBH0dR&Xmp;0GFbS=4e*CD02TwTM0my@GNRb^hJCY zR>~LPo*qK!{>mOmAp0NSc(N<^w~Z&qeUp*quT^5cW^{R1#%V`-inBwOEv7<6=t0H^ z*%6u)!{r>nA$(ga9O+*JlBZ-DBgE6xW`N&BuaQ|0tUcNsExmo#HY(l`^mtU0$U*bD z*qU~7QM>V7gE58i;kdz)$o%i$IIS`y%8GGwh8)#k^G>05bT?9kp9)S$j)?1g;86LW z3@LFj12Hz%Hv810-s@1#2BVKHObwGtwZArN40MmKbK)9H4RkrOKP!;L`AbHQh_;@$ zKl+v_*9Dy)`>b&hmtxO1G<_Bu8goG>8r~-8JF#%$2posLF{m{xsnGtpK}JED=i(c` zx+`9EPGP3zgq)Xdq0NtJV6=*Y09YXGhnpt_hY_={a2U;~v+0mBiNyLh*c`L3cv522 z&m3}i_g}0?K5yq8njA_8N;@(l>wYqF8kJGwaT$$`@t(emu-OBNpmT4WMY2MD zj@*}-o1Qm1I0xAHiB_ypG=@TQf&Ssce|hE?O;o;qp|EyyYklx0d^4EKavE;fCu^1V zR&ey^Pae7A$gU%TXcT7hm%RMi0LuzxRf9Qsx8V*o{;9x|82{{6F{o@|3$wqAKj3*G z7-Hr07?Nm@o?Vnt>rFzyhe;p4ol&$;##ANLM=cAc?^UTaHQc&4rllFIVKi8ZYn`Zj zvtyEE53ai}Q<(e^F-@LdqR5vnSEo?&Lm|6J>BY9A1hR)3*{|Fl@l-yt^UmS-^i-Z> z>VCqahN68Dm|NtO6wHZ)I{l&XzkXbhOQy*rz5BENn{TYZ@NZ@!NHjWcr4Zpo@b@th zN{Mv>3d;p!qm8@o6DFVAJ2RUVB)>RAT=QK2J~x4_clVMx2g1wzU5@ajZr3qsxT+=_ zm2(;oaK}sNvYPLCXDW#^hcwpYCEGV#Ag(y@GhQc+>_zYRH26dLXy(UF#}j_i+N$J$ zt5kohh@w^Q8IA92MVaUie;duZv}0)(ub4XS)?a)b>xy*??j9pi7gqd#c>2nKsJicK z5F|%INZ95(NxUWWtu`_c0GCPQQBh^0B#@ss3Vo`sflneN-tyz?FIZHV@2Mfm z+@z)HKiJ~3@)pPsprtLi5+#8tlIz%izNiXys};j9VX9#oQG@lys_QA6*0xNO&}#N z@MNNa^!R3tD0P=5ipi{$M)gtbx;Tb{FDQIr@!>%tJSMSj$6cD%R|q5S~JAh7!oK;cWKp}tf|uyD>?i#Y!0 zBv_$(`F!MMrudyw*i`!dmO5g;2mup6 zVZQxwa_-(%Wgj8^nLzwH@3=l)`9HOWizl)r8Dlb=;y3f#ManGe9!}ou;l{YLu(f;F zm=*6EtdTUr^<{sRMGF#lO2nz?J@$Dm8i`Zx=|zx8G8{6lxkpDPA>A>j(5%$jS=a(b zt&>gY&Z>Sh8+*jnBIvRqlKbwO45M4l-o_wtg^P3O{21j6&KsB4os?EAi59_ZZm@EK zj?gW5Ca6K>R#gt#>@WolLdRfqpY8`vHpF2Zy6ULnz0<|>FpuWwHr8~6IDQ)snh{%F z?vaFHnF^&dg8tgrKt_es;NG|5J}ox<7#)LEX*M0iZQyZ|R;O}E5`pAQfefetuC-ou zV+KQDtAEf{hs!f!A+q_;gu8Cpp~{{ub=Sa%_FrJ$@h9=3jBN}vZ>oFa#(25uf<*W8 z)ra*P{SsO2KdT)<9xmSGS}@r#>EAs!ri_il=)X-|csawWv9dSmmR9nUA{1cO3b`-X z+-N*Y=AFh~BFi9v0*2Mz#m(v8>WmUPEXx*c;Obd zJS_XBZEIr>-lc!~yHUC}I~>2F6MmKP0>J2YPFMEImf@rU03FOiZxGEA{-#Cpfzk3K13YTv3`yb>0LVQbQir>HC+Q>CBK2JNtsJqer7sSYS z#VfzLg_^GKqhsJkGtPBc;23mzO6cvp^|4g9t~&so!xw=Z15dpqwjAVNzQ&YbI&2T7 z8ZmGU(X13$|8l@V*NrFq$X1L;rg6ocl4P^&Lay;=c$6IFh@BHEg0$>UFYq+^_kwQ5 zWmN{X8Jv_G0`ZHeWsBaZ>tik%{DIj`*3$R@uRFMusg=~jA&uA!f2*?Ql4h|%wYPU< ztuY+M9&+??lrdUlPkGv_YkuuFZ-t4=(-|-JOmlnKM91|b%0xgEQ$(Ms)^KEo0gWX~ z1KY@2a@WOH#@3=l{97>@lJ148{qj&&wTKiQ1{|hEwnU})Fl`>`!(!3>#Kn^NK~>(o z(3d(bw>)(}S$Q?o$)=e*V12nEAH~jG`IEfc>9!a$LD(HbhJOQ3EG#`9|1t|Sc*d-_ zo#5)Ey1stN%gNkfQT-zehdcm_F_ph(V2h!=LT7WL2c!P=wdJl=p`^$f{z-q_O*ky*Q-)WeHhM2UXyQr z%qUaPSsgolLCRMz-F4+u%?P&J_6uXE{jX>doSm35al_V~#;&;+h1DW4*NimPH2y9o zu|DVoVv0xS;=%IAu?-Sr2HKfr?n~NEmp{d;Ue6t1aItdqoo|2i+Urui9-j+S_QdF^ zP?S0;YG~P#X$;+VgUPlc)N50<&mL&Svwv_Q${4EH`u@U-9ebDlM-{9PgYGnG`eAhl!RB zdN|r+rfowmG~zNmuBG90_?<)EGB!zkf5fV8rQR|s`xI7qbTS~%zt(fqG;n%L+l0Sz z`=0&IiL{x+|zN({=5?b06S}CFpFAr~Vy_{+~i%f@ExY;^M8?Uj@_i!x~ zgDusI@8GZcjk75>aiNNGc$Vj&h=jo3SxWa0p+RofQAJ-TwD_-HjL2q~=6-8a2=!ZE zQ=_sUkgvPxq6TI%#PKsV*MfR221~`t-!4k^)yQKK^Dp#r=G_WH-KwNOyuGnEH^<2N zYW6lBp#sQtW8uvN0Ms$2apY4|Llb6;Sd7u0jTzH*NzKOKMF@c9UAyIPJoV4(TWJGf9fR<&9Z z-UIb4nBmt+-fWFo(Q^N1K86T2Xvvw2x$kdFI*1~nOoF9~&C(rWhr<2l2BZDuBo4s> znH<)pYJ$tvF!Eyk69L_xu}L=-mjF0f`l~5$dhLf?1nbo{dZAZ1P+yCcrwfpl{L3gL z5fUJ_o*#W-E+yNpAwtD5WM zM^k!eDGMu4TR)R1D;S!ZW)MZfl8yG6u%v!^isSg|05g^xWSMf8zH(4KCGkLrpV_=K64wQzh?`s&Hn( ztCLKPg3zz{ssqL}5`me5!~;^$$jX6O{5dgmg@>|RR)=HYV?%F>FuWtClWnzJ_+kF|AR>2`}~B*J%RY{q_rfY*gkXj;Ar5y8E*RA0klds(m0pt z6~X|MWEItq9214#3iyHTY=ba?^%)IpYG%poF|$~u*}SPms!;N15kq{mfvV(%p1#dv zO+|s`Bocwpb+*idig11WlSSa z{2J5{u*~>DUD5fXMqbD?>KB~qfL}1bJ6&dG@b~L!?V-Yes_y#+vZ!Ir+ZHC1dQfui1*V3>B-}k^L&P3!d28y zx-3cE&lNADMPeoeFqtaMGfeGV2@&4D%d+zfN?9J3#QHf|xNVVJ*Jn0GZOFZ?5zZw! z4j=UCTRR~cYWy76)6z;#p1vNN&fP8T8W+_MAu%*zkG-jtH383ut0Ya0Kc(J}SNDJY zGwiocJPXkW%mj=I9YV*lu+GrYQ{7H@r?UGDbI`g#M#Lat{X5h`yf-_EwOUVbd02Xr zE2KMh(sx2Vk}|QKjx)zHE+|3#YYg1WT*->0P(zQNoO z?ETN)*VYW$jkAr9rcXz@=V10VrZfS*4%O18@y17id-*4OQdM#h=ci5G2kAg*^MSFE z!{v<;@9P|4?hAXXOJh~}CL2WVyLHeR_V04pFrbd@Rfk_Pf}=67`J0bU9AphCP`!o_=#|&nDpUmo zF#i%el4W?`J1!V#7O3 zD!IVj0n6jQ?hE~m)7XQ%GmX4H5%XB@$CMUn=9u-j8J>dz_qPwQ$ElnytP%N)jkQSv zw&ambk_s*EM3TOG<9yvl^VSTTA|%x=Hu{OV4QeJo$_=P!v zx}9Pa_2-uV1h`eI%v{jotf7|DVfs@RtIsYd&A7MFMeJWyd2Wt6|3vGl?@RNPm9j#4 z>hi?pz!&#tBlp(QQSqEbECfjRnH!y&O!&dgQjM1z?89<RG6K#26U-CJdfVDR)hxL^O+;Sd&~p+cz-qqWuryS)df#s+n6Yii$ud8rtPhqlC|+3NRJsD8 zJR9G&B~Nma&~l4R!s|I+P28^|ix+ftKVO}Gsp)Kc20$yM@gwA1oRH~E$J^V<3FD@C z;O4E%Qk&oyNIzg`~5)-DE zioF=#C(eL9H*Nu7aIr`U?DWqOqmyx~F0i*7HWd^%>hv{sUG+Q! za09UAcwMulmE{vCH+VgfDfGC*Csels1HrCvqsIj&Cx&9__lp@Ym^fj!JRh1cA?f!p z`sw>}VZH0e1A$NamD`gVU7+!>|8;=3vVO+pjA7t7NxRy-fJo&}$cnw=d1SUhtBL3B zW~%}4%U@JyVZkvj@}=5)f0_gRcAS>J6;!c{;ZqOoMFkG+bPcWAVFn;7&T`Z;frP83 z6UC%6HgARLBz<15S8W7J&8VL7p2{IXfu@wCaMaV&vs~1%l4Rt!E~OQoW|XhD5DJ)O z(Mh^-`AGD+DMc`|vf3Ywplqv{eJkH{&7nq}PkTc#sx9=job`8(0XNFL@Tinp$CU?K zm(UsPpnXGbsohFC3BqIU?ZH}+ zCX4V-e@jo=g0`(Qzc~G&T1{IzXbYYvI62`RUbdr5hmogennAflbCm7E$~V3Q_-Lc` z#E@zH3+qoH3rPuAYe3gM=t_E{$x&{WMPOpbmC=4}yG`?O1F5`3uq_bCVyh zCw#b%JqL|)ENZnFzA_|ezSykVI{mg{TXh`^PQ3Z5iiI+2fgAgcIff?kkf5D0ZPt2f+3VT44fgK0@wK1%`-_zly&&cqv8n^0aGbivGRUxL9UtqB%-xExYT&^o z3#Kp2udLI*?N~8Di-A3|tPiEZcn2J#+WGUM{777$DF}oF?%Hmdr#ZbDzvdCLRrRn%uJRcm;)-J-)rC z7>Z;OYJBESNf}H;3b0H*+o6KjjI=8g3u0@3FQzc_?A*CirA0O?!`^yMY-NzD>q3e1 zL+q8s09-;mX073!qJW;2Q+l^r`xbvw&*IsZ6aOr~^pEQ4lv`SH#mRd&1v1uFH&^1B zrN!Sorn6?yBuz>GvT5Ls7Fd|MrW$Oho=lj?8OmygbnbGi;qV$UHuL8CC+)LuX$=0x z&^OyU$gWiV^)Ul;O`+*>m))k(xpHLyGka)l?L$XyM~3KoAa`(fz=GSiB^p!ir_f9= z4L@_luNy4jNf9IhQLB+Dn57_<_2aUvoPfk))GV9ggXDWMU&J43Ifk-0x9({1`s7-2 z8n4YUHc)(n$Q!Q1Zv?GKX^+^i!`I9vE|^eIl)h9Ur7pf^y4t3n&47kYexpT#t(gXbz7;d|NmJ zeq!FeuG%vYai~Yt6t`02QsHdeU-SR?IUZtP8U-Tc2(SZfe2S;Z1YIVNUz@f`I2wY4 zLU^I6@WI{3ZlvqW?v3SH?WuC;c&0t)C&sF2#O4*JlzFmWveC8HA0@G3I#EN)9R(lg z`AHdGlqG}J`>jg;9!Mhm)kf-H+UGQiXk<&B41Z$h5XcbA^^_H-|HLTF*C_t6qW^*~^U>+e5p9QKD=iAGd*(t;1-Cn^3ZA>5se1JEX>cY?S%`$Mn|2eS1EQ6h6 z*c38t{-t8tjMd+GfkIM-sO!2}91{`pMMAG_wigA)Qm_+TUCpk58Cz5v;@gDBq}9s; zF6?~xjlP|vzinN@$Rj!GVIWcTFQ5U-n^Ct_Y@@R7`FYpI{Y=YZ`9)SXP1q&2VW&~O zI4k6+MQzP0NJv8^nS(1Pghed^CR9THB8Z9D36{ZsIcZT1LtADlMwXV!Qoj1j71|El z3oQ5Sv%^Q^Ivj3Fc`zkRI?n45fvW<1a zpV*vcQ$G5?bHk@XFwZYaIZ9r_gK@gj8KWi92b!?Cq!mg1G6S2e*^Moe%1_!qX_rg#dgER0UigEL&v~`%%j_p#8X=3r5+wd&Z-}pFXY7%atS+?aJ7pG^HGGp_L9GJN4r9Wb>mzE( zjdFeN6$j6h=Pf(ZbI5Y-0O|D(k3x}ft(&>pqMBgdEj<$84%&4M-$E&}nHDQFYTh)~ zYad2pkHP}XlkoFGj2F1%2#>j8uP(l0_J8`#`V4t(2%!vBEE{x4ao`C zGDqR8saf?z{`jHIAYsepYj@#zRHO7>*ny*ET)8W{c4=!axXze-W_BquW65gE3LB}$ z+EnecDo+tqfJRay-CwB?nj2s)iusN!FWhimEii-y1Ty}W@Xnw7)f8Sjr$(e1v9Hn) zYf2}SkDd)pbl54R5pG4XxHN$|Onr?jFaOhNpfE$m*6KceSAJ-@(H9?a_5$hBMHD05gl3KPQ zKVcniy-Uph(*k_A3ZjWfUZ4u00tvH_3vavF;?4$TDRM82s^>1?U*geD;Z1gff5_p4 z(@b%2+&)|C8ysV8NuA!`mnZ~S>iT@$>8y63IXy!+`|OC0rit08 zCS*V=cZ<^6^~IOmz?cyZlIdkXQAZfz+^k`=6{MRdw7`|*TT?cFDEZp$dy!lYJcEze z=>EOR%G1-Mgljb2WwI<}e*-HK)ngVi7Rm4j{_Lg82H_z80;sEaf*x_xA`mJ7Cjd)9 zFni(vu5?Aqc(qIaLH=O@n|lFPPJj3PZEXCz9PFiHS`~n^lA)jZVE7rr(>4|QzThfT z7HbqUhZ$?MM3RWQ6AY1K3z5s8vJm+qf)%g;Q~f?UOjh3{O1cSqm_*Qn)?_quSQ#_F zqi%X!tijrWC~`uhK^;*LM5lzCnt-}A-%6p?{p_J0FNb%92}q5^d%L1X#@dmP&o4{@ z+L?BnqHBQLBEUGD2-{rwt6Vm>wQ7c)dO7%nQXRjm9Wlf|Duc?8VjyGyE=)mNaNHf4 zcyHNIyu%J)_FIP}E)@MGBN|n`U*AIqzyGYR?QUFM{d*?DQf*u2V43u@dLo_xiv@$8 z;F|g$zJqWLKL=4f`=@)cm1S$Hj5;zSRvVt)Vq<^78dW&X_70Qng*N$Y*a4w3pUm_x zzMs|lzv8lh>t^1}cwh;<=xDD3E|ZLMPBXc%!x6_f(O4o<_5}5GR>*?LmrAof7)%JN z@&*o7y$Y%vaC&{Ggpu`b1a{%dnO<3_>b4hgwyZ&*X}I3VeydYt;&?jDhpkZ)(qKh8 z({U3>69P0`Y6LqzbrfU;L4Tp8Pc}u7uX5{2YRV(|RG5#xNnh9*_LBed?C2;ATAde} zVmmJ?E;SS(T!4*+bc2b61SIG>9VLiF{@QWN2>%3Y#Uc$<(BPsK7nk@(Ff*0WBh!WE z-;m77MBoQN*~-zow9;owqbiA~AEFdLkDPa!5Ay=IB(wfijpPr=_W#K}8>LIsXu{4) z?3qMqL?Xd*EdQK?NWOhjC18jH!VcUEVE)c$4h_KlU`(0)eLUTyaPd=<^l$95E$-n#--%yTH>V2LxQAH{T{b+Aap%H937D3g8HGn?No2SaIn zw?=$udq}<9++M}5WX+eyVZ{=tjWNl2M9z#`Ua%V}z2MD87tsJI4~J8CZm^D=c&L)o z6yA=%Bwv^-q~(cNn+_l6U;dQkVyGS7%4_Rv0=Rwyod@(Ed&HWut09v06CPXlodBr$RS0VjSnzSp6th!0r|D|e77>l4T;8F zsOZH#qX5o3x7iUF|Bx4n_{-TUJp%#4F^H33PYyF3wDb!m$-H}pA>e^7f!6x z;Zz+vunYYN4Ry8nmpt7CEn3hv7aXxpu+X&J0zU=#M@DC{2s>O}7&%TF8x71l=*NbG z_pQbR4;C-l1nq6vW3>j<0R9W6!F0#pX^k7MA55~?J&tAXnwr-swB0dt#%5{#g?Uny zQjlQg(d<^i*fO~sVl-l?%sbY2XloEH2JvW$Spwt%SV(l$inGKI7zn^D0YdNsulGEg z3_%?fQU?38B3;S3J(0i!xB$<3FzG|lI>EOKG!eb}rI9c$o%#!7x#3?btStAoWxcHe zWRTf8Z0AJu2c3Tz0!9G<{1zsY51K|pS76qp&G&V+I=-6fr9OT?euIfH#BG-zGugk( zXcQ_t;sd%sN&GiR7pd(;-NJ*7B{RnwZ}DCj~Ru zN{<`wrD9ZN2f9pDr)%$ z>zSp?7PoL~HSS?>htYfV&sL2 zV-*>bUnqik7dy0~m_geVp09Xu*Q*yvsZj$%^Kn5k(0qL6H)sw#W-Kf?%|8QO_}_f< zlrUbDn5mXK8bkG!TN%+O`T_-CiH$y`dZNu#-7IPv@m=O4>YOpdaSxE$gCVP6bUM`I zGz2%{&^E=R0s4+7qzuqKwovfUf7IP&#DZwf*PychcntFAHY+1>?CZMn776^Xj>Bk& zW9=M`NhX;e@7s!|k1a_`Qhd4Kb0ylvT2`vAY}R>x>026-E)|-;^VM7DA8-urXD2kS zBpkoQjn~FVdetiUkx7Q`6PGZZ zwjEw3-b>}2@J#z!ex_2#rEnOg2K8*<6kZw3y2#Nz45ji7|8HH{+%gryXm`c%>M50W zreA-Iz8`#uuv5shxU-o7`{~7h(V^VI z=A20zGC8UGFuh}Gu7Sr>bnGKS4Y>#f53*r0%+ONgsDt#fNEVUiFi|+5=4pw^Gr2-v z;V-6FrnvTFK zKcX*G1z(6^&f-zbXwqLdx0p+4lS>>-&Z*80&f=GwG%B}O&}VaX;}7Ynb3_>H<0BRF zD@5Efw^MX?whHFF3aEHRzwjZZFH;746l8olTM|=J)Lcaa8uKx>hE$p7R(B~G6By$s z1}0tZq4J-m2dJ+fgx1U>3eLp4$Q=nG8Y@L=# zZbhJWzikUEINQ-WiHz(_@E=<++cZ_3 zg-buk5$)X5^V11)CjFom~0%&3^(_=tMi zDn7-UV|Bj?jJqsz+~YF|SMn|1i5l7(1E;<|uH+Efp^@_m|E~5iz#P95{G$M*V2%sT z0)6O!WBc-{wTd1~pp)rG)k=k2@GB;wu=f!m+4urz!H(@bWM4QQF2^NhuvFn>XPJMG z{>~YPd9~Oolx68Ub<$qY8mhEd*Fe8HSEjv$jKw=6gGZ;gT=`JPM_ash z#eXa^yd^IL_fnrIxrw$Vgst;>GDW(Z{Gc!dCh@dkd}iiJWO0N3|M6I+%W-=6VA7dw19!uTw?Up&j;=He-hZ?ze~<)Y(&e4Wq%ca*O^D9g!*OQFp)|h=V$D~ zS6O5H3$Gq+BhZHr!8ui*z9{&z&N)U%}#w0D;gn#d!|?Q{%$mf?6)hhn#%*5Jzm)79lQ6t6@j92 z!F{R3J!ck!i~?~M#wUXsbk9hK_nF(`+VNu4+OXXpk63V3E$N8cJ022Wzb?tJdO`FDFCx4x}2@y$Wx;CnRF&10y>{o3rH*nn$VD&n)OQS z!WwwvJmQczr8v@sll3ni1A`grxk@Y&;!fd9BM)R4iPe#KET27y<$M*%`RZc( z0B30~Cj^jmm}>;;o8t0L%ey|33bYV>wlskn*ey3q1#YQvS&3}vXxEI4N3xf<7NF&; z_xp}Cg+N?KaYNSKosW{e^p^%;u%a6sI++N%^y5$9X~?EE@D9Jl-Y*e~kgBm)VK$U~ zG#Z{Cic(h*&PV*b|K(hoMcZ!&%LDb<@CcN5-jB}5@=tSF#HH*;!;4;T1^=zd;9XBM zF2G2GvcM= z6D*x4O))_^SszL34vZ_A1-nUPF5OW*!MDr0Kc7}3;f_~4!p!bdf$?lG_D;2G>4iJ0 zI}4xZu|Sc#zLiz+iu88Uk@rzUkR9MZ0hnuv^98$gnq8HU;k6`{7s`}TUV{h{|GI5J z%*U*-=)9bFq8awIsX26fl?fQKGw|%UsT-{HWNi7RThqQjpEA8o{lPn1k2KrHlZ$j> z;ovV+Z55c=)Qd7E6V`M^McPl1YDBLVRCuMg=`Rfjvb>f0JpKX?f^b<(_iqq;XIMc7 zPu|&Lr8RvZtK1GVMOD8d%)9)+6z83RO6DdBOjRJ5DOPWJs8z>xeSq0cL%DG;ecYgU z`tuupF?>8HmWhf|-`6nx>^m(mb97040&P1~DDQ3I>RgQ$O2q+|@SxM4PR~G+wi3zs zECpy>a^2rZrc?u*ww!v&FLxSk%c$Pj+l?wBL6*#Z+U9vEKx+Lw3q~4JL`#Aq*D!nE z4rdYFQS3|`Ix)7DaoxHRGaYiu?12t!mTtedNb@LjE;q~_Q3fNN&lkv^3jQ;x z%#vSslSS3B@k-gNr|5b*pF zZQpA`SElu9HBlO8^vbF&9IdQ=2mlUvSu4ey4{+x(MXI_s&5x?3&Gc;*Tqpn5Jf@n~ z_SF*o6>5rn$#4`m_t)re1PCI4|958YsP+I|Kz% zPGSei7RCnv{OKtix3^o~iZs`oZt<%pYA5QcPd03fy8USj=V5!6s+>=!?vwQNujG!w zM<+R6jH`kUMHca1L)0mN$*lmBkGa>4paK4nrLL}RoUg_^X-M*|_ugG!+|inOK*ogV zvFPayUW*>R*^{>IsF41)XZ5k-C;@$FjOg?4n|hvwdyiM95nn#7qLW3G3>c2oJjmeF z;vuh@cGj_)-ZnwB?{=$Ipa0dQOK`8LEPG_Py|T&p6d$weyML8Ah%xFWAb)vfy0`%A zkMePS|D4P5*%kr@Q~dPxsI)9}NYFE2OPoZ9`hpsGy(Bhfbu)Tu?NzbL#p%3C)%2Z6 zmY9AdKt%XkM?JQf^!Ax7~d^B4k+Ta_lEJJ4Q(nz9w?*)zW;e=ZU zL4{a?+=9^S2c3DUo{Lgp2&TI&C9{@Ww2sT|7IJ-wDOjm6Aky#M(UMhQsDk%MZym4V zFAMeHSL0~H!NSuM{X^tdb+C4(4(pnWy*dn~{ErYW9;6-NK!DeExDo7x7xS@yP#d~L z+9?&*EAtxJ#)A+WKiDL&5BP6x&>e~{PSky>;rmD$?10n(&0=yu4~(=~@WXYtn6M7J zEZE!-zud%#ep)@W_Gtz^e%=9?h6SYSkQi~m=o0Ezq%at|38@?fnzEjwelu#e;&_(y+Lod<5& zCjvc%FZo9`EJt^^?;#u6w4h7$dZ^*OeVfvDs`%Inl;Hvmybs1p*AmOuKv3em+C}C= zs633^6^0KorqL77W_s-cr&6*U=1z}ZP1AJm@MKL+g>){AfC|<+5vM}=0e5IgqEBp3 z<9hXojMj)l-Dx=!{MLGpp*bCyC3k9fwj2zPzwTL=p9U5lG^NA*ACHYZ9E#^Otm(qv z-#lxt5VQv>d8EiHFaB_B%CB(88j?CgJ>w}AcZ;AJEK|6hY(HcS%8vHO|qjPTYbs|spTflfENRnBn;|o_WE5`kE4uD{AB65Hr*4V4aCzGHWJ3RvJ~O*hLS2 zR=HEGj7y!M{3$F(=3ix7BVcd;xHICx%O{?sB7mj8R# z#6~6(mZo97c)d;KeVO3h_8^YYuN)*O- zNmAktJkJ2&0mnC3RPVe!(H@M<&>Jkto__FRl-^gY1aQ)ecfbz8`>eU_6q`k~@Jtk2 z;0Y0F_mun9t(MUyHPOwSlxQXFZfI{8E8$Y7Jnx0Xe|v!`Iq;+HHy-T)lw}v;i9(Nm znedA}i}r`xv@q)fRtRR0sfUB}ihU2aUf>W}Wi{K(nW2RHkEWRSCq{c#k#-lm1D;yp zT;{hbWQ@;oGMbu^ymN&G;j+^x`qy4qWck&%_?^&rF8vC(f>#&^rI82Wk@Ivi zpOGJ4?MAiO0HCn@<$via*Hrk45aH3NHUo2Mss4g&#btf371(g)ny_^#z^a|Tb(~kh zrCv92UW~%QhHbT#vyF?}JIOKwQHeRlZ$1r{&v(HAazOfLBF8NQuCnL*N5SykE$gULx_!58yi3;R!->VF){f#2|=YMc9tKR;<$HMBY|E$#M z11g~TZNG*BQ+vx5lbt1c5!M>2^`*LV+k_K$@VWdUH~Y>SP zuY7R|)gCm5jmFteQxuiW84_gvuZP$=}gzEP9u#a|*B&;fxF@%cG0 zf=oP=Z^Kc+v4Etiw?{#2UNtAkc2#B14Uq zjrZc@W#m`;DO0U6JuU(Ej;1>C2c2%1@S`5N-sAq^k}vV;R`VGL!=C}47UE9~3{u|4 zV^iT*HqSX?=&EO`h*3JOfs5lGC?*q$NiJn`XQ57*Xkm$px&c1Z(Tl|rmXrO4*ZEau zgRA*o1MHSAbb9pm{kDP0)dGxvD-$oz$rF$e(Bkz-*exH;9jNWwLt9Qe=S=mzgnuZ7>2uvvwxl z4Aq`H^yvPawwIIzJzAhzw1Lb)+p0A#VW6C&A-=UDT`%LiY9e?}ehZ8c3cckd=MA1^ zO@a473Y6}GSiCpd6^~Y=K83A-I%vJ(tWk% zK_xFA-&9Xra87>p3=7k!07B=OvzmbaF9UUyF;>G2S({sXIkL`^3H83>FoJ^jynvLQ z)fG9da)Q=`5u!l@1;i)fN-Qc8Pu|8RC?$S3X3!OBH>z;7O`yhii}%2wdPqnmp>^u| zi|daAJ-L3aRx(HlVNSs7gin7I0CaPc(QxTptz$LwYFS1as&Ri->-vu61%#>?v$C1RD;XaeSOBgBxp&3 zYvVB_^2kewKPH!La#_g8!3Z+;^G&yWxZOs8^y1BVB|r3hPOZjEX0zw%v&HSp?60hR zbEXa!NbC{(O_abj7Fd__J7731`GY;B|TS&Qs?nmxaa(Io$ehG2}yc9U|>g zU2mu>@aINhS@WL*#Uc&}r2?%-9@$xw@%LAg^^9a^Z}JMWfXF7ILXE$oNb1d^JrD>Q zE_lJf0as+x`VfZK*QFn8>65Fl=YL`^{bF+|Ol}BM3jn(hFQ%cSS9$@+N9U79nr8R` z@R3`8R|E_?*6XMnT{d2_B%NRV1zzd~PUu|5vWy6cEKi?FnFhEnD{i+9G!+M=EN~_e zZ)<-Q!`M-ikb|EW;pd4oFwo*nT6&DbMbO4#VLx?>Zec{O<|dOL{y!~1UbpbHZ&fmP zQZIn`_|irBpv1S)R~DS`XL~cc?|Ln|{ZSGhRvuz}Q4&c<_{`Cr4h3AEm0}`54*p{P zaPzf5S*=vL4>(i=!mu~lWSjdj0BDD#2k7`d=K=N!MwlX`r^~IqJNC*@rGRkBq>)u3 z4vIgYZy<^Smba&?2}}s>Sblb>U2-lh6VktH{cZIqUQS{+k$JPmuj{@RiMLIXVn57XV|4Vu$tW95ZPI84}172Ef2F40Fi&3QXev znMK3jSODeOHi(vpgX57vpcAmXLpzOl&cLD={u||=RlgtMxYyN_i*6mrS~F$xsa=ND zBMn#+6%nvt2o3yLCuAa3e%iR6C(UGh?EVQ#92rhEaWDdId$|G_5bbA>iUK87b3l*R zoP#aJSeO{<(mlsGWR{#=7r+F;7wZl9l|}fKnosTI5lGbvUp^@_9n!PeN;5>}^qg&< zcxa3PBn4ll{iW|dXF9=$|1yAt4k2HZ;dy&_q|K?R_s!cyApZ9r5*T#;K7-|zn+{vj z)Bekz|Ek#=p!8lEd5>-50Lbzmig>sf2gLDbr{4=EpEJaMw>#&8&~wec1hWgZ&d%Zk zpOS2Rte$b%*d1v6e)1w_{kM}x>NAdg9sB$@j2y~>B(F(nPp&`$oYxOi8lvy~=B8H8 z%jSMK`;C52h>+H~NR2<21r+nrNxi&r3A_vNR&~^s0H_^S1P)uynW_U_E>vQwVjCdp zJY8pS2Nvd}*(?9K1v?Mh;=QrjGlp_9`m^%KJaDi`M{{&>Izjy-$~u3kaxj04o~!El z_gniG%`y)$TsJ&=&d8bZ81=gDpBRa%1D4tVT(f8`&eLtx@Nl3<*qjy+$H@7fsq+r( z@@oe8$!WbhD_nKY(|qc?r4r7{sTlI-QHIcYFxa&GhP{qAkilg1Wz9$tRznsZ?K|DG z*F2^%gTK6yisOsSDeWn@x3B^*#S@3;@a3IJ-m@uVB)WeDwkDmR-J>e-ee=i1q$MSD?PCb6O&N0AHad>jTR1 zoF2RFBrFT=R}q9)sAPyf!y1~eXHsTxhl~7=!WRjd5X2db_)CC0d9L|hCl*}k9*Vav z65>f^7?-C3yvg6)sf3gxfN`bg5neaDU+lgZD>xu+yww|Mh;IKrGmzS>+;S{-mM4a? zL?|eHg{kqcD9TF5C%ZPX-mv z_7sZ^Y!C+lllDE0ET0!&)G#N@n_@K=66ZqPL+;*9GPE5phAeu*FNj4U zu_lJFZIgMl<$4(@#(9TW|IYKp%FHBA2!HzH#RMFU$8Ffi(SCW%0@C2w8M;=j1LcZ7 zp;Ruy<|Om-J=vys4YTLzbO|tmuly~~(PjC5S2!>JDpEV3n>`kk&icZv_nnaRGvz20 zoENPfM+R?yCRsYzi;~pAjMDXsML3v#uZeT736g9!87`2LMP=CF<7(v)`}ioLHwMyI zQF*Z$VxKtD80dPVFH4oks8t{R1_!O2I7wsqT{0zG3ERIm31zHm@+0GJtZE@kvRZSL zIxQHDv+RnU|JkS`xi~jg}W*0y6RE#q$XkvRnq9!*MsTAOP*xJ|j{HBgC`y zySh(zn%eL*h@HTlQm;hpiN(m~G{GZP>ddWayp%qa>g&J-c@`KPt$#`$!?$ktyj=Em z8*3=gC}Q6EC>!q+?@SC`$3bs_BsKhOaa-a{uS{m&HaZfilcT@F|M1 zP&jTrGr1`fiBWoy2`Qw3q2iyv6KeoV*ypr}VU!o*G6`?u*i*hR*-^*KjV{<2rx0Gh z9u--WM-8XTPGsUvdrnY=8afx74;X4>kbKG{gJu75e-oO;5&AEcX5a39AtAJW2Tr-1 zxH0A!5IR=20NU8IO$_)#LZ;s&MKa@+^iq^x2T-vHXTBBa+wuIjW#y&4IA_bs`5Ed| z$pL0oZjsnDO}cgB=KAyb2b-R`7L&<8ny{FDzgVG_VH9?>WP#8amCAoIRsHG%>7L3) zY|Q_LyEGMVuiYDaT~o98-zuL=OoCCUtL?z+WONl%qm^$cW3~5?@9X(jEK<|?>;yaT ztWh;Vb?PrREv5`9a^;y*NSC_L`!q$D7(H*5IZm;=ET#)KfbX86{-7IZtUvyHG=RY@ zP@i`FC+dafily?(i|Hgrr5f}Ap>5Cq$J19vRrP&ct0+n{bw(p}2A&D{8WEd*K9YRdku6QbUMQNP*Jw>ro+j{Ov$Yj%OJ@~- zlet7!%TwhPz1)16B4or|zHc_v3YG6H$-fKZD+5bF>e4vZId^_jtp=T7#@lBIp`kQ% zCC!z4&!!viMRpylcmjK_$e*u!Wqtaej|rk>>Zp%IhfjL$QO|7yIcEuleVaN@Xk|}{ zcSoWk{Y9E_j{vWL{=;*-R}&v}BAm|O9c|B*k_)jNqivYR=J52SE~L2$&*2iU{LX*5nCWrOj1{4fYPrEBea|aW zXtKq@yQ*Z@B@^Wf=nL2^V^xq6WzwM=Z<`N$&aB`W)AT!)?JfrCUYIjU*VN_g%8OLK z_nRpWE<5V~jDy&bND=2wo=ImAISH>JcgCDamswp7BQ^n(0zY)z?X%R-@1(y;11ge6 zt4X4im@N!pwM8AS4cT;&>Qb=u^|J$*>qj~auccr&_O#z)9PnEBnJc$QPKTZFn8<3;Q z#qAd$0=9*ps)Cq^MaiQxF&fVEZ2u#o)8$EDo$?LV(S2@hkv=`=D0lnSV14_|$l82@ zSM%d(yjKu?h1`)LYlA_PZRw=rbUmns610=ueXIyvlJL&1ZsL!i6q}RrPIZ#5^Y7jF zx^W&3*&kr9lsB(Oy7)IkUvEHNZ5Yeg@8l<2DG^!bI56<}}{tFo??adIs0=rNZrT0+_XugXxYs!L^6i4NjZvN{+}gK zsmAJ_SLjsCkQpp?+2$k>>z8p_g$LNPg?dolus+|gn2)!zbs1^ub*pY#UD^GB@POf- z(V3rTqjpfw;rJuQPpszLxnTXyScZ{ZsCgcdw?9W_u~qoOjA@eAqoM;nlYuC&4>f#BZT9Y<@~ke#}*R? z34{xA$AvE{u$Eq4T1Kf1_8&*Y_&8LZ4uZ04W!POy|RDeZ1vQKUt0k?U%A z5~AF~@M(z&(=Ty5*8gk$1#TnWJ^nqks-(|SRbA1id?Znw^X-Wr8Lh-_S2L@ zrdrB?_#1D`WSF{{FAAZh1c(MHf$L^lf2T_mX%ngkHBU>k)WWQbYNiIQNj=dO1y9~v znXx5Ws~uFR&)IaQ3TMellA~#Evh^1P>(EFNrEpM47rw9S_(DTq%v%wC!bKVKqh`^( zL+=ZZR~ti6r~b<@tbP(qJ%1Hc6&{VGKZpsIA^W6 zKduoiRRjUEZo^1^j>aEf&(;Q;*|=vQeK7PaX8$VHsfCb`Q6}H7oU&HGF5z#`)3b5h z&Y8dw=wb3<&E_i8;5eDK@nYVN?udZSxyT~dsOb#m*?x7?vuWlQkA|GMLRAmq3>$}W z{c_p=th|5*hY4o1i>6B1Z^tNbVo-RAp(LGSD0-0?cms|Rr8HL; zN6kCix15jOdYvW4yF46|63*WydEJf7;qSa(jmtTpQW_KsaC9eOFD# zw5HkZ;$GO(uOmipmExY38`#A;ycoWqM}``D>THpSaAkFRGEQbW$p2~V;&gEBX;n!Y zgxsA@Il;K9v8BoH6XxV^;cYE0363=Gd_$S5&nyRxv0-a7vVI-!XXw}4p5sU(zt73) z2+!H$QAyldNXEK$-bIa6inl#H`a6qrgtvOpa~5`mJho=p^{o;uSS(RfdvgqUO`Y8j zS8>LSRUh`d^U~2$mYbA3o1J2hPG_nQPaoY+^^va-Pj=f?(+JYUc^|SSUh&nOu^ufv zgy0;xcj_002-b}al;C@%S>f|_h#T_*XMfbmrEGL`nv1mrth~`_mrN^-qc670>6*~% zl;r-K1FF$PyQ~|12_gSb;z};I`B97R%eSYu#og=<@8I}S=#DbM z&i2-nbbYrKFO(YPNYZYj7lVtN+r{v-DYI{)v#y%{xMcBB{^=$g#^_Ia+f|DP7dN~- zwwBJEX-~LFa|5)wT_fTnQdY!=h-lefKOB=!86BN$#q+ll&aP*lvWFSvg_=}~-_iZEv)vb)8-Y^qS*C1FA*d5rJ1wRDoo>nhg?!eZ z`}%R<@be1PoMfN&bVueq_-R_~1={>&$k131dzZ`^)NUzfZX$rb!pBKJl}xkC(2ik* zyGwu+Pyk0aK5T1yZ+3-Jj#gxx}uC#3j&tfN{k)BZG9_&rq7 zd7iICo>*Rg)zwfo!y6*t>OD&HO4X8i9j)?{?2)>~qz~%)vqmHvZZcd*gbS zwwKC?HKc806Ed=Pe+il57+w^S3@s-(&)VTir9;{3BFEXoSx(*4J~r0&@OEm8xA9tF zU??Q_+?!G61~gNm_3`?F+Ytqqk&VlFivoUI4( zBZh`U>04gS`<5=R2q%4Bhr=$nz#Da$rdA2Dw48}U14I4PnF})ew&n9-j@R5M);lBU z4QbLEY_FBdUv2alF11<8<*Dla@Fp$k1Rof)SEHd}xJ6jdG1KL5)wiSvEF^%y1>SFghW7XVlTNWtku!C>OT!bI18*3Zd zTK|+e)L7X|oa_Hn0+!0ME;K%!tF6>WsNVIQ=3$upaVJ#U0Kd(&YIyH(c}A$~>9!iO zRVUeDC<_Fg%(#J8Qv~@6*~awxO+110$-|$}X9)^uUC8*WR(w#}PPf2o>s?gs#io|| zTP7Q!tPWF|l)JSp7tj5dKC)3C%dd_tzDL|nKH_s=AMkyO?`s=h6a=y%QB;)bDxMRoO#o5)wSD8F5Be&8oT?6W0LbzZAvc%7dI}T3A z!1)a#$_#JqNKRz(a5^cGyNX>u%vjmETBi&hX|MGqCWFX8f*-2KtPZ^H%0{p;$0)OZ zCgr?#;#%(-w~HCU`5*<}5e9Q4pLmvo!vn9c(l}884zpL=bUZ!(YuhtMmMd=CQYzixRTK1mttV_pDxj* z%%|t+@oHdr$HeCBej6^0khdimMn8qy86TKJ?5{|a+(vS2Bs*7=l$zp`8K{}N`xa`3 zioZ)byHg8B6aj+})Rc*CzI*<+CH>2OSuH8iTUgK3QjBHUmN_HI`H&EaR|BNv9T}Xv z%muua^>e!jz@J`*9>751#fG_jTNqE1jZk;8fft?_c{oX zPuG&uPrqOBJ#>=?Ecj9t*zTNs(D!TO;XX$fLq=qt9`W;XBq@D2tHkOzVXm8(6&RUA zcXk+#pyA<8KamfTBNMA{*@Y8AVxfUOK8$>6wUQcR+h_LHo6GVk_+0(-xA0clw+Zw) zCFQk=ZyM1>T69Y@cDR<@Zj*T&mWh`59OJkVP(Gs4T-D40hd8*iVuJ}Syg%=yzu8zQ z%twV6SS$r}onKE2G2gcBjj*Prgktktm4NUs~x)`q6cAutQCm5x`K%b0N= z(6K+c2VQFi44UfMRQz4OW|g65AOeEh2%IwCa(lI!JP~n*g03{imGmI_Qqvse(1~A;3Slof--{nW%j}P)*hcW zb(Ew>XH7a3=E5^~&qv&*8V4V1nlcAOv=x<~Fllt;x5&1@=)fK^24SGCFA^B2K6Y^P zgO5{M3Bls*iHove*0{lbLaM$3-Umj{ouN3mh%EZ*g|F(b~OpeOT_w1+-y{e z&Rw|V@#fxxwDY=|azrKU$)Sz5B|%5ByEx&c8=T)9&B_n!nzRp}xiCB|>0d#xST5tl z+1-{(t)qx6(PK@%DcoyXzg(5mXq&t1 z5j-fm!C(26Vrx$otg$35?+5&$gI$6>g5`Cc)p@AxEwwg(N^d^gXM(%YEGnJ|OyEd@ z`!u-ifM_c_~qc|TgKW~v`Si2Q;Rp;iI^m;om47onWln+Ib z&tUS-*>iWlLRBVQB0~=~xBK00?Mli@X2#(8Qc)Z11`qQ@CtM9g#zI;Q`6ac-%%Fmy2 zH=<44g2pD?<1KZszW4B_7%V+WC0xE+(Js5WLDup z=>C(Sp&VP{KYG^R4~nr4K7%v^BQfd@}@9 zq@g@4V~;Y6;HNd>!0;Pk!Fl!6uB8_h29}iDS9vdEImpZ50t;W&YG5-mLwOqz9nar} zh(T)Y)1y=aG0g_ohKlKPsc}IJ-nMs9fh*e5wt@pb9s6*f3^UTs?(lhXwCtb-sD`|b zThh<6P?iFUxZZdtm3c=x(hAoB#ZqyW5*jWrmPG!D$Jko>#tDhlqp$Q2jA_PFFF zB9Fh@u^WZ8>+>8BGB+^wojkP4d*emFjhw<%MK0RVzzPwW4)T{pf0a8CK_w$*M`H3j zDNGO#nk~aHG(>N`G8+3r>>ED!gn_{oP3Yz*ntY55 zEDm$Xt3vl|YtZ%>lTGjlTdf0!%LTQ_G}I_(MyCYo`h+y5j%Qh0J!r8HAl0FBw4Cuc zniklWcydDeA}FZ*;}Had4Vv{s;hPoSsv>o>kH7)b_g+r`H91(Z`cBTHOpOq9?)~~ zK=Ix=C9NbLx0R=HwTjJLDmHeJ#Vs>=!`L6oTh-GNoBF2X(n()W!IAm=!}Z%A>A3}& znFf(&>(vg%8T*1K_FEM{NPq$5h7q;1V`6@T4V%D6?$JIwK( z(d>(f>5_nt%f1y<`0-!GCI#fya&&ba0I0NSO*I#7H5U~G@qk6DtrSBnhw+KGyJ3W5aD?g?liLB(2Fzin(~;k3uco#YEzk@};cFvM!}MLZyU^iuxr=la zrLadhqPxr}CH4|BA+abc-Ap6JNY;Cl50snviv1Z#`wfiy__ALy?7r*|zFBz&{{#1a8Pir!Fkl!D{$ ze3vv&|Dv74v=D$GK2(vIOfjs=9dMU{N`uK8+ zM@^Fyb zKpdn7+uoVo-Cu8I9OC71%0oMs;>N&aN){4(Lf(SBM{i%L`-y{KWi7wNWjS?d8*7lF zc(0$&^UYpzp8D&F=Y}7>b0*+*!>>oAf6C&MVN2Y51rFTnov5gm_+;*1k3SE&uD2Xq zu2Bh>jVZ-~F&d+=(tS~!%9ohL5{qIx)0{cY^-?u3yN)5Fy9-nu=9Kv^pZ)3RD0~0W>+`KyL zheG368(dtk-!T5Ek(&7OF1+iFNS41oNQxT!wyrD<%zr6aj5w!Q(}cXJn8r_#s@!Yx zaCJ^8e;xVac*8IGeh=j#4B|kaL@>0i!pG@cL%qe9(-FLfTac+!JuPcnH7;STWp{qC?`sdME* z2?*N8#xP>42~Wg~L90;}`aWNkY7xhuxmS00VkF}R=x7WSZVAa`I)j(Hs}73?yjn+w z3YxCh$u>8WELNR{k(OHx7NxpIwp=_7z6SKJpr$rZtNfyF?xU>7w^*)V-25r$rwH+X z$o4*CPZSR5qWO*Ja6Y;;*)c!M#1FZr`iR$fG2JUIcbr83&5(lmn6LI*^JbP#?cp_yk8c~NW5#T9^ZQ@d>N0R`Z z0l;a3y7me^omao@uV#pqMVp}$s$^mQG``9!M=ZyHDry4Bf?#RoOc>7e!%4^46iAaH z<{PUr@T;5FjMI~Tf0`lk=&uyz81uQC9KURT_AWLzkfz?_4Sv{KXDQcp@FrtNwCswu zQ{@|R29S4@V{WozE?zRHSNNB@^4P;ko{l+;Npr(D7ioHnbUFe3;SadHI)lXw91Lf6 z8p`yjgh|s5ye*dK@SYi5D^{#zxot6z6EOwEKDB9UrZubhTVzWyQ^jfx3&rV=x$~d?hwyN5%G|Flrd14!-0db;&(+>bW8N>m5ThQtuZ^FXFqB3j z+`MU{xb7H0D6+h^vz*$rKbbwTO94JF-l^nd@L~wA>q|*dch$P~6JXnL=m@^Cl9ew( zbISz7BqDd+f?##rD?jvi`Rvq+{{g{rkazk*zffHlQoLur$$5ntlNj8n+gbbCW=^}-v?9~e>dd9@Y2KQo=4x=t!F`fquXEbtq}7Ulfd*shuC~V z-B6+*8a}smkX1zb>O!*3=9IFx@Ul_0ip#~es^>=gS3A|V#0+%LfXq(pr|9$v) zdBYB92@q4iZSjR_X?b+*&!VE#BZS#so&f;&dV6r{x-B`_^etdZn9e@N&|B9Sze%1E z#86&h$z+!sidvZT_P3KIU^a08CfX z1ORHuzGcjSxNQwd#K+$lKYmxt-&noZrF~v4L^`0zQQ( zCwoHO-e^+EoV~Q37TUv7Iig3-H=ej_KxfdhwXxbZSI_f+2wbI${;5l?2EnF>79ygn z+MLVfG9wK+^HswcM!H%=r~Y-DfMDqx>B3ZFu?W<$Rhrk6;He=E9P%Swh1sr?2Ba{X zzl{(QVg}RrdcI32J2qzICGG!$Bmyvs@!x&|Lje9UoBMWPKcRqEk*5MhzA~ihibM;zmIWSi)TZJCZTixy8q*)e0_jshYhbLq~`_Oum>mTqSES%ls<*jHECfzpajS$%c>Y<<4T?54b{%-mD+i_KC#IRCy6`?T)9%QUg zPx`6&oZxRKDLR~}kv48C&%I73=o#|K0mkGEy>@xRBoHigSQ9yiCjo0ENz1nm&>IbR zdju(&m#YCEt7AADV4)hG?txd9ULDLNGAH{jpm0KF zJ~~4U76aUPS?$gmK)`F&crZ}n)@nOi|epPe!gLTxIk!MNp<8~aBehvFgWv%>)d4R>oi7(dKp zk`b{v5AU%yG3%s1Cbfg2r0ugggkC1h7`R5EJGg*+nHYHXV9k(KGF7*-22IwsF+O=$ zBE#2}pFx6evX?V9AxepBWMt?=f3&m=XgdfizkI0inBf&yOolXJ`y-*X&8H5<72>S1@69sr5; zuKP3|hwYFn%OX2{$0R2!&1JyHsSA{+0xmOa;WY;@ON4~OGMT9Nv&CsZCxo|dX@ycu z;+&ViL)J65;K{>-o!ZL1;pe}8yk5+=vN2kxx}8r&th_2)zB-*bSA4iXeT`UkW&7J0 zJ51O^sJ2qa8|BD-;JlZnIN-ZvDPU)S6_hcwmS!m*Wq*XBM!Lj1&RKYcqtVV^2X?LX4+N04ztdkG@ZCN)m@@r%ZkGX48Y&&F ztDCPGL+k4{i7J-X;frG$!A~~ycH^sb{qg=`H7BNEkcIo!J-d9e*)_~_&xaW?2d!uz zYqRZUv9tRNWCJv8lH{=}JnvY@6BW?d%3sxWgcKBD2l(h>gPjTrjs(mu21Gz!IEG@x z6zJ*vZG`v~P=jxoV}2}kP61*AtLATPWVb%F$CiY$r)F%q~)P>#`moS->&`c62^p7&NHh z#-Mu?TN9n!GmtpPa+*G_Lkx>;zn#b?0(HSs?PA5neN6fzs1nEg*4!TxtvuZ*V}xLVjFnmp zga*9}8(sdH5ShlQ1pz=^Skv^@Tag)?LguIFcopaZb0`SxfVfENW725!m1FSKx4knv z5*yQS0t)i@)Jd3ybFud-9*hLVbgK);8}m)&9YQ5_F*U`^)s2GoABm>G_G0;Qm4cyW z%+|(G1)ZJm`@xD++ZC`II_@3ZnIKUCv@kI=z4Ui0|gug07dPK9A{1 zL84fFc$Hni03yUb?+$VK$e8blQGArD!uU>0+j)gUoW~==RdG4)Y~FH6l1%bg$Cwb> zc}3M4g2nLGp#jz35KC+z3rZtMdg7jIGwj@S1NP3w+CL84coew(T=aPe>y!NQtTv?X z@%!D>Nx+L&C4||r-{7@Tg1_l1%dQw~3An0p6BVuO?CMxrMkExk%nv7m{K_scLZ4k7 za_$^bSnhOX@Mx1Iexw^PJMqK-yRVF5kW)nF=EUCJ-2vrdsl-gWvIRk8{WszQ>Hi5C z-^elcj*|C|8i{t(H1z9LKLASKd1X7X?C6pIeuaMv8p!V0xI$1#fM~sOqWM(AJdror z{5Mi*-1aHi&A2w2SwNuiTm~zt_^iWk?|#2?%cbx`?+Ld|Q*U2eE;GG*?X`vH!-?1R zR{h09Zg%}Lw+@AoyXK2*5Gw*I+lfN*tORdJ93IrcG48Q5@$Js2nbIe=K=g_K1iAisAqL$kq_H@e z8tKy7##HrCgRMsxDXRiueJ&K` z=6Fzq590P6kV7BKwAu_;#hHuazkS~g9JvBWNV&3+BkJMn}|fJxM4OO(TS zr8x!H@u4V??TtVCN6Z3TX#_%=h4sD(xBR~GN`{c?>yY5sW;Kz?OgvaXeGMIIuT8ch z0#yu9?Zjke;&4T)pldt(vBpa~*CS0NZ!0UsS1lENRnT&k66Jkiq%#-(P{7(kvyz^N zo~VXd2?p~#@m>CTkn?Xw`2%mcRp$`@RtZHGPbcP>6}^HfdSzxuhm`xhvK!Xy8%(b$ zk$jE z?2kAr>2G5{$oFN&jl2G9z6PPwfWCaEQ1$;PnTOQm6rRRHeYohu*~&c}!oIEeJj|!9&bslRdR&m@xkGO#*G9*EOU26pL6(g5 zb}KeR{i_yRS}Huo@ob{av(EzuY&bN*Ysv|Mu~SeOV#%4}o$?*3br0 zE{GJCwci-`d(L<=_V&Wxj<$rkv%nz(H*3nYo2$i&6APbE&TVCwsi5#fk~UQBA8+B% zS9tnS3%u%rk2ow8xk+RuAT1VjlnQVhCXw%V_(8xh^}&FSO=pp+TLR_b_U?|lQM$CL zXS^)0YJLIzA1Uf@V*BJyzUs}&r=IHlQ9pq{LJUh?ND$S;DIz#E70l9qv3Dgb|RlYAAlSVl+GYb{%G1k>CSFSNG zX34GKe=~N#FdTX^5LV!lM5OlpdN$mly?1i9Av4yh3@Mn2dc|1=Smoa)QDi5gAoJdw z- zL>%tzB(?QC6^G^ea=DgSVFzj9G~xgKaHjV;d^jmw@^{L9Ys@!sex)J2oj*!@g1$lr zW(tTKLRF9KbvS4#TM}OOJ4EqyXcT(mP+~JtSSZWOnr_!EtbZd3{F6N^F(jf8$Nx63 z+h!74m+q>q^{3zdw!hW9We*5CoHyG+hnTiz1L7yAu9%}&7KiOqp>>s&ANHc3y6Tf^*Q<<#2?mSgHenLl{Xm8-u(($B^_Fk-m?8|^{gB5S4PeM^$EQpcKpot8vR3y z_4?zx@*ik@Zo%f4QyiwiVb|{tz*!}I=JYvo6v*-qtc=m>TSa+kySV@MPPz0s%X+}@ ze^ve)xmO+bY%r)?p}rro9$e`&NPBkX+<%7ezUs@WV3IQQT!5sNnK6yhV^u2lB!xvc zK99hc9M@FXRUSgfH`xB@Q}TA81h6+_u6tt zc=YolrKL&uCh1+y>jjJVXBks|PLipm4t zRpYW%`M%R0bW3K6#}|0~F>b2g+f3mK!1xCiKS3X6@oky{vpO9JE?S?bVE(U?r{HDs zFmU%J8u3T04r1H4=%g@sY_fOfaTugA2}J4e{TV#d(^W7xplJ&c#oz(|?reyU+5sZ? z)7)hu`3yqQZu$A|JW=l-GD_nwj!Tl=AxTMZww4Sz(ie}po>ht4|Ln!@Ej z-Gi^5kZ~3(tvl$dNAIyle;E1dJGd*yhAL1tZt$}hRp8V@|NFPm#c^w&eBPG_?_JpM z`mm_I94>70C9nj80!GkVPAzM7$ec04fB!sY)np2y6%orjrfZ!$@yG0|)uuxJv$*`$ zns3N~Pt0o2urOjUr4RGKf-|1gT$Yx&61->FYR&DGpY!5xyA$1|p_;zi9#pD*QIY2J z%0Mv2#Fj-_s0(-X`DG997lebKBaxCptb#N+$%z8C1hd}UYckIaNm}jjb!u48j8hYv zKU`J&ni$gFuU{gZ=6Ju&p1XOLH+`8<`()_5ZazdU zghM#=x7WB+@N<{ASGic-$IXTV zWGi@~74`t;2)kjCdmXQlNcD)EyjDtOX8#hR=S7qQwb>;_cP_M=WJ|`AqtSLVpUh)R zmn*|AG;AW`?dN?|ESIo98Jm-Bl~t*Hdu&m(h(#>8GB|ks^Sx4^XbAAWr{ChXBlR=kZaTt^~1qwup8+;E*cm@;1^s#m#r zab}D0uHpzi6ASML7G99Vv?l-DtA_8s3#qO1qSr`8_5pn%0uECKbnNc05 zqS;D9*}GrBhIYPK{-%VEgS)=O-Kr>Dl$ee+7*0uvl7<~nBNHMi%`#fpr{@(fHsZI< zPF22Tn%tupx6e5BESG0cu@~3czp6sb?UhI*7(#AAlG$t`$(9^e5@M8xeD09k%88iM zSvk})=HtKm)-Xl1o3}Vt(qYnj>=0S^KmO{G2p2(X4MRd~K&vpNEBY5MrB@PeQe8T3 z2x5MAx*CYrCfNDEZZ@fJN08wX_K1#*ypX=ejEFl|tXEtYav_ z0xS_9OSGLP&@Y^=MVwL$_7Mv>c#g_wUNe2VeR4BF@N!nghtxW8U&0os6k_E1yj^}y z1{{ddi8adJNUX`FDv|iVodAHNYO8YT(ofv(oWtt-zZG*7%&iuSO z4c9^UuJ&mM=nW{GqwR+6RHr~O( zB;_B@j8nuyB#08okZI2X)8cLEem+w||7w{4pZ&Uk^J)oR#R6kmVfMTu9UW0x!mxPS zrgtWW8%6nqS0p>6>mn?&M6+&?UCW*L;$(W8(pV;a9n>2bUgm%fH}uq4c8rD3FNZNT ziHgECMO9$G6%7H4Hs@&?6$M_L@PUEVJq0UHWxQ5Q=^WMO0&LI4t{B}^d9Q3|*FcSG z`gC#*+_8BB7V#y1xqo+MwLHgOKfJV5U&mu_*zLB`?vYY<%}XWdt_*^fa{e%jO%eR7 z+*sL;V+VeS^$t7~>VXrB4MZh{s5Hu78HpWA2NXB_$1mRG#e|>~^c6zA8{R2M@H-GF zBIXPDnu5F!@;ean@I%0sinqV+K+Lj=h;sq&%cd9YmpmH(={?iMQuDFa?1jZ9tz#|; z9))ABGgr%?=t!!n=$n&Ka~p)dOi!pb?ne&V?+ag#Fvi1+4;~<9vxkjg=bH1{tR3=K z%2GDZBy%_lsHzHCV^W5*f5XBRAk0KU$Nz># z;hw@y{H=>Hg)0Q7E*(wh2Li*&LHv*`!X!SZ9Ao3$qo5Quk64MB%~5i0$m7LN3>W+T zty`MyGU5GLYn_E*DPN=7B}}5Fm&T=sh#{+6LQ-i&%|3sk0aMq=>gIU*Gfef>aQx89 z<79^HH-Y;35gX?J(!Q`r{)hFkfOL(;!VskV3>#|xg6#Ql^o&y9-7ls&p1Y>ew!)`l^oZG8O>dYiOSgwXmuP3|9KFQnh>oJPbGSjU{I5Ee3EZ@*V_%XII zS9HXW%f4HIOALQ!v7xeibn0PeRd8Wu?s&hdt$6Vqw?hj~o=hC$`}*B{kjQ>M|Ht=C z#&_2-GR(Je$r-5nCB12x0SgXah0X#dV&}!*^`aEuQT<*#f{x2B+@f?7Do8*BLH}Ev zs~raHUPDNO)tu-0z`;>60qN1kF|~HyeYTu?YBop>n9rnr3jOm1S>oNb=`qzgFqm@b z3a$SS+c}#164oHyy89BY!0uqn)3lrL%N9~WXwhR-8n6}0NLLFCc{g#_1Scw9ak^?k z7aQRfErydNjt!9NN}hi2WiC40A<}$9Jet@hpbR{le_q+SET>1v%;9{V3E^4OT^9df zUOP74`;Gmb7$ykK>5so^zPs+!Gcuay2d`NyWgF(wOn34y^^X2()6uTaMUJ{XHLQmI zoeRG_omAs_=9;pdDicwS1+yuqb{5b(T1b;55;@vhL2Tt4v=A+)Lwp&%|FB^_{JjIS zc>BCeK`+R)Ktx5eKPP1P9&Mt-^7or?JOwQEyXUb;1$dCltYO1XaubA4VK>tTpzQO1 zg5l;4BczQmQSnL(*_GwJFlYCznsBpOz5a9{e>o6SiucVAfAAhR@^YinkxuI(eX_i} zXn;Jjz{PN;*{SBUGJbbWa2N>dz+JR)<;0wFbPoeX>RjGN)WnvFb1jbFI-LqrJ3}9_aS1tSQu+z_xlk zH@;6@x=U490!#8n?w-Yg6SxKk!VCEP3{L?EM{y*uEJxLzyY>^vg`qRDaxYAYFRP%k zF>=A4>ty=nrqJdc`F_`2n6_^MaGgnXI(%T`rD#8GJdv?uH0ql>KNGFWJnm>6$aBRH zk{13%tfdjVf%&U&6X<;$TRp!x-PRiId!Ef2M4*Mv%1Ld8DCld{Ir3(qW;HdTfQQNa z5R#Y~(17<Dl;$yveg-OImA( zA^O#kO!QQSSXe(giYsGQz@fB~a2Q*l@?4%`pDksu_?oh65r*_PW+rCRAMz|EXm{nP zIV;YM;0ArT*uQJAz?LsS}?DMZch3m9ij8t@b% z8oJXYU%(Ly3$`ifz9Ba4(nHc^>VSK#i4$*Zb&VA|&6v1acN^~SkWOD2tZi)kKsf&W zZDtZR=jT+A(h1qUnnYDFo*jaYb4x2mrnfliAnv(6Rs|HI-b_Cj+F@s7XT?6$2N=B0V>lSxE*isLUh zv`W}9Xeb`h1%r&@!SyU)_Cyg1KjJ80)kS|`F_LY-y2~d~9~(lY3l&ug{u1Uso?Mvc zJ+jqqQXS9RQ9nlnNi?OUrUl-|TCISs!`)kY_T+CsBxn7nOl3~!#VOhkSh~K|1%9~;PgA&f5g0I6fr*Df zC8p~urY~sh&IAq8>fqT({S4X+d)_2~3ePah79;(@*`!M-H*+{L`8?gv({#RMdJV*X z)@!)fd)Q6Of0tFJ)Q}G74R%H3CYNw&v2`2**l5sfey4#0Bz58cRe$Z;ve zZ%eDFU*4ot^ew~IH=YCjPna&5Fo$9+h?lB`CoF~2cVL?fJ`1*>Wx zUcw`#NIUA=E`<@M5klIMUbZQ%BMvFWR7}}3>fc~!gE!>z%by;O-}cMRKW?4tWI0nM z84-vtnV-NO9GXelMIBW|n!J!#QYi5}mH)@`cv9{k9l<<(L~x(E<6qWMib?F?yoz6c zBV=xMfKRtoUs~VyNHERTMLSbZ zHIi$rP zB28}My{gym4m&;J3beJ{UFP-*HSeAefPhs%2mX$bLYR8(BOY;s~?*g`1Rv|(GgAI=(p-!ejPWLyjL79sg=5!obK+x#CSSWhX!HK z=MAj5g|Mib3pRbYPZhS26O9h{2Hi9(--^%eNXHf{*E;3E&_~`+ICzAtyA8kztii#~ zB4}f|X`G$_=}#hj+;hH%b@~6@4erm&)ns$`t=EQ2OP+V3nFWl(y3vnsKin4(K06b_ zTe@|l-xHQ1JJ^v>x7ER)dYs6uIa>xR=Z2nS21 zUmH#|>9Dg_u<4gaFMD_9ND7%q;Z9PS&S*z$u;mRU)1!4EXRh}SO2WJmE?%i?pQJSE1pwsiUtTXa`z&=s!pTW1$GVAphI~TEcN)j+G^s&3YjaH}IFP0sviq z+mCxt+_Qf0J-ZfySRGlUT-6*tu^~6t<@mR?^Z94@KsA`7E#aS>#9_xA@$s4`DCLcM zWYM1QBw97vI0hM0_$<7+lm82QhT`+%YP*^oXv^K$>fdj)M>UjIb};ZU%;`JzMO+L= z5Af~?YwX}MRyo=XIX;@G0Cja!PJ3D%ccjxIQ|ro)b4O_R8|u9)N%weIQBmPT#@fxC z^ior}qoT{-~hM`T;XL<PQ*)0@hJZcWsFVT#0NDo;^#yE&FACs(16X zVk2i4^}BPbvB~CE=B#MJmf+=x(Giu6MYVyWz7p?;9#&SBm5qe~0Rhe4005xh1i9y> zb3ZioNU6Q{b#h7r$+4lr%M-sS>=u(G#`?`(+tz`g6YAbme@9)am@9ciDQ|UJ2fw@f zvA(5C(w+h1Uij17BY&RgUQ8%To2@|4=wNHHjQM`>S$sWf`=%&QJdrM`VL^+ZfN0Wi zwAbd>wo$k{7i?LRCwKd~Ijg+DL2vI`cU;SoCo6c<;{wfoj{y-k?|b$5N0LSJyQ&Gh zDTz(NM8qRW3Tdb+we^+}`@LB*>e1@{(_al?MOpK(Xz4eBKW()-O?D5D$Edu8%!@Fb z$A_j^EYbDRo&1+ocOXfzZSx_1=?SEfk%ux5*Rh4#8$(&~jTOQ-?DB6G2#fDvQ8u|K zwd9|v%(-LE9!Rl40vA7N=ZD>tL&d-qbB^^30I>5t)9ZHD?Pxbk7k!O8J)eVmFRm#3 zjh2Iu?k(HpPugZY9QlhZOvCS4WA&!k8c_wp@Wbw`VlJh3Qw7GxA}>Jk4t>+OB7RmL zO?iAW9Yj+9d5)AL{3=oWRMKW~HPuDxa>h%V8V zk8O@hFXoF$=gZn3&|IfRwzOBu{Ys{4g`vMn8Q>`q6-^Aku`{_I6=b9!sG*DrPY5fO z@8+*wTMwMR7~Ts8T$P7=y=XLsHSsgDq)S3K#bfWz{4=lEZuUv4%ApH>3;+Dg$^Q0> zN!&L;_>Zfnpb-lt;~=4RX{omIC#R&?$Cd0_5gU^#_1}yge$rrcd^&r5JxF%4#H3;- zg}H|9#c_wgSq|M&;6*RTapt9g4#B;M%XI;Bo~BMS5!**gv&LIYiI;i+8J9^vv)&Hm z457V)XVjr2(5qiDupE>A4*-;dHWu;;j;>p`gG~qS7un3X5`VbFy~q`Bb=qo;*j4ls z5*7~q!y@MFnrqAvDb~(SZN?RIk-&CqnEB*p4xid|sm32Ge1OZyIl)uOpdNa4FSwUz9c1&=f~{I{TL8?e&zw**L&pGXrNB1hSfE@OI-sn2}|mFh2Own%{tDTxu< z9Fd!_@h!L>c1!Wam_=$H7T17vHG+i93uCVlA4CcfO*BuM(4bCH#}fkT*QP-m`35s4 z+@#r8bW3DN>S^X#)O@Mcz>yh~_tZhNg_+S?@Q16}#$=IfQj;9$h9v!BEaDybKIsL9r!rjF4xkX=_NdJHo`)DaNGZO^wA17lKYELG^UA1k!MLDGRAel-%z%*_?qB~|UXJ0|f&`*fd20XBl_!4~2C7iQB ztP=Thf2KnZX5SzAPZweLLn&28ubl+KSeTR2LYR|ob|t68RJp=xzRHx?%9=?} zx8>Q34)LQ&+M1@4L_ zKCTimRwc{p$xKCZQfoVz*{InBKfMXY9_&c&PcT@y-AcZ)l+tBxK;Uh)s z;sePZ7H!lIrK#QGCmmclu3RNz4e%OmR(3bWb|a5R;h>dd7ZU`KD?`dfo_M+U9Wx9p ztf1IQ`rI^yNkJ9HPX((x4LA)PO3@Jm-JJl7&$EYiAxD}ow|-VyUVX$0OqZu9fx?+; z>fke!ouc3Jx^_dl=i>=5REfh(j_(qDYT9Q1RAl?lX-F6rhE z)7ZbBrn`aM+_;dx@)X-OJ0iz;w&Lhj^zkZBoq@%i9qyV52?2!jK!3+W4C=-i)i5-{0r|K7 zmKpbbHF>8ZA8N@CPQ2B{hQGxPyS<)kz2Eq(4*Sso!>kMhnhskrDued@ltaBP3c_p0&7yQ>39`MLjIlJl~J(2n;Rtv~9~Lsom!K z7s})I`M{L)yi}_p6V8*ybtCJ7B`QJ!w5aJ3TJt-n#4Zggjz@&T0X}qO`K~;U+8{?qs5^3E7!h7FB&@0zuXJ(&eZkzk?m`Sj zeonid8b`sG;|N02RG-0_^P34Und%gr+5Smf~Dz~X1N#NVZuy*#>?tsyZR17CdZD0 z#%cPS42@%&L6+e;H~}M{$C1p|-1!}-xqo;sp84wD{LEC@9FEaR^}N(3`#8s18pyFn z{#+EaE{wKEn^W%R)%f5qXpEGBE_+d=uA9RF9|%l#C<_Nww4|i5%8FrsW8uv3u;;)% zd%j7xK?wReMUPdF3_nE5d9pLuG9v^W`Jze%*Rs_S^HB$7{tp=d$P4SssxT(S##&jR zKmuWkOG`8-^X1}C2?x^)%+*NCNeUC32Qt-jX5AN};5_OoD-w?|MZ4OBk)))keWSre z86RZVIaVP1$5i95lY0~IR!OrrP1!!=X#k&81yy}~WPU!>5eg>llEUKkmf7R>K0^A!DVvsXAQNs>)}=>LiP{(CD@N7VIlR(zh(=1D?xk#-<^=3?6*uiPo#o+ zyDl*%fqf7G1r`7UUc?@~;?O}VXZrX)6{F(o=6u~DOf29CweKrOlrcfQmREUT8Z(29 zmF3qqfUg;wO}+kBdVP&K`|q$eIB^7q-}sEU!VDT#zK%YQ1OTG`fmX1#s#v9Pq}=?> zmMRI*=_?qCKUqPz&G`)Y)AY3IWlT;KfCfR!&?WWJiNT~lbEIDC6JkPO?2`hQlZfQT z0VLP2{Ke+_D`dD{Jd2Yb&0iU5OVJ+|Qbiy`baPIO}+dzT0yDi=E5ie;0k5 z4O)>jMA5IVdC!UNdUsfqS4oD z-#=Af5wxG8mDEeEln6tV~DcIv=7W*6nNtOF|Wz54Oeb%HUTE$5%fQ z7VB<9o`4;Vr;^n~K5QmzPm=SPc)M?U@yrgbN;)^0bnacFIjU2L6MVFhv2 z8bCQVv;!-<5Zn!GR-sPy=So~kF*`HCZ5$5mlovle3SHd@51IbHfEqpX_LZjw&__YN zf9}72Z`-`Hp5QKM)=V_?tUYv$FdQ!FeN;nHPSfKOY!r3t0zX>x&}%m5@JPn~&6Ixz zwwb16Lkcc8=SuioAxP6m(uQcVG<1eajdkGtjq&;sjitxxT`g6f5gYCDF9M;&m$nVRUHs5p24ZkM6cR4aLO zNC6!hC9ALnrqr}DW2gkF&=c&OsoUu8ANc9^C182pG+;Xma>l)ShfmNoPXL*rb@_ZT zuZ(cVdeKT4&X|OYSh3VMGKY5m{f;& zihg~0Bk`*UR)CHT!D^{nC4W~rL-iqm4qVA<=_dA<43%&_3q{Wgl%Ev15B8kf7cY&(97QLCmqgJ*MRwwwb=DFA zfa1Qol7ilzRCpeEW?3M7D{R6mXe#SmQ6nIW6V5(#G@uxg{eA3l})Y2kHWNJ;eyH0A98%KizK-mnC*?z{?0$`8fTT zqvVckXb4mUjd=e9D}iVzoYPfi;xQp$>$OA<7|x*u+otRA5^wvY#&th=>cqPPo&4(i zKeomr!TMneKU1Hxt#Q?5*QJ%id%c1Nfbx|Z zn7@r|P$?Bab{&N5L`ZffQl8rW&J&9RU9(1Mx{o*M(@CyqCGy(YzO4jHoqnPR$h82= zSJwEOzdhs*5fO%@fY2j-(kjE$c#09BNZx1+?KUg$9`bAL%94;O*ir&2=aRcK@*Pdg z-PxAS-7O9lYThV9;iPEDxhSwh1M(OyxX8I?fZnFo4<;leheXa;^YdXl9w#kX?Wga! zRtrebC!oQ<0-!=bYr*65OM@aiWo&jP!SkYZ=;X!z`*r70mBdR*hA%hAJQKq@H~T&! zc|=L`F8n){e4W0Sj)oGFaU$B7Arlj@&kAUQ4hN8eSODlH&q?WMce-dPPi)2NP4%Lz zTkd%J^ai7JlCM|JZTa=Tx(_rzfUfeJU{-?4r{)WEvV-5dxzIN*|>nkbJoEk^o{9{+iTTpwloFcCo zYvu$0g#^uaiQx-)gX1Lcadz?jcUGP%)r|{f7X2N%L#c=qNQfRK2rrd9r~wf4UX26( zI6+t^g*n|gJvt1k1xfLb)ZP8hH0Tq3vB%Pj&Pm^$lNLobL{8`~2t|05AF6`mw=e)(R!tH!5U zGw=}?&_t@sOhy-hwYy3&O2X(W{LA=_{|F$da4D zHg(3%%tj#R9Jr&|aj6d_6Hn2p#%w1N;`gr!0pMFe_^>kV@MG^()XwEmao1ARPRO|F zhDaiO*1&ADShFlEH+$Coid_G9GQw8LS~}v2rpW4F2-e;&CqQP9=MfK}KP0i_`gKFi zuf}miem+H~E-w{2u}$Aac5cZ!$Pe;}T7yHfmwx$tkI9}H_SmaoH*{)dOI!!PNS1!9 zN5JEThs`8-Z8e5?Kpgn$>dc+_rPGvd1T@@H?PmgLP;10cN)ejo;bR8W@)x zdb-!>U48UrmFSV|DvK*g{@k9r_q)o6K%lX3u5;=*8`uKd&RcJuSyqDha@#JpQA(Pr z%jG1+>UWjC`|}my`3?thGb5uysKV7fGY3?RRGym3mA(cE9h_^_BG8KWC zzi}8J-*jgGdH%+eok)x_4aVO}M4yMh;nvBl`)ZA(8GX0Co+b*cib8}SFNU5Qoz8ro zyLy~*859KkF5@!&ImS@y7GT$6bCNU{3LT`TF_tG6zYTFy|-Nm3Qz<0n6Iab!oZDkz0_Y57}H#kO@M{!b3w)8q}27@c^(-Nx1`Q5jQ> zS&}K0&WL_ohN|r$A~MFiw_34UwvV4aIc?p|O#Ugt942%bqOHabd2z1Bj=0zFPwkK< znap?hos1W@g_^(1@X{O|{;&_ukhQa;kk8YxJpfk#7WO>&BV34M`wSQbT;TN zy|z03gXG?Q$WZ$@|G6yX6`H=sunm#TxBTj{-p4L;1VvFrE(DE&hhA@dFU_RaxZJw; z`1a9}s6fXs*nnzc>ogeSV`)UlX|IiS;7{oZZaP~2@a(%^n83{nuuvx_j1#egGMit; z7;_?ppJwJ((5A&$$qnOc=M*9t0%du=3?h<*{J803qXVq9PAMT~LapCO1Hn8Wd5T&@ z&L)7J9r{9PZgN^?(%Uf6f71I;>5$qpHK#KCj{UCgf|Gmz zWlx(0clcl+f0OGn?eX-9ZcH`?<0olGO&8{LGpdsKy(S{|9`QQ?UR5 literal 0 HcmV?d00001 diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_curved_frenet.png b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_curved_frenet.png new file mode 100644 index 0000000000000000000000000000000000000000..f834a64867e6c0a62b37609f4c5eceb01361a9a8 GIT binary patch literal 76194 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

((%ZrwfGx>S zIIj<>cl}+;9+(qGtTb5H|Iw9W*N$w%oYAbtMvYC$-t)p$f%Zq^!9Obl91}?llS@ky z^LO7*4G@_rbr54oxkyx)u(vg(@qmGlD@0^rk75WI6uPc4{rvOFgHrRe4rZpQNEMk^ zIIg=*r)%mODwSc=BLX}&tV&D_#K$QHk(hxh-nTarz}lQHf$e2>7g&p;T}m*wJz8U< zycjb0uHRl9Wv7h z%A=5G=^O|-=i{%V3y-vT>ZRzKXpnZADqUiaWNX~}eM>!E$mlBKQA^~uAXgz=BSkeK z9xpf~8q;VyJXE1=C3t#@6Dl*M;ki=nW~;v8E|xSVri@i8e!Ry*l5*%_LjK{35PQNV zZ+;m-rg6Ck=S>*NK(^9eNwiiXFt%YHGH2;tibffl1Caxft-cRgmBXlyt9e!m7fE z&+y_s=8!;8{Z_#c()s$EH-SlOtG{Lkl0qJ8uUXPAy|F6?%0x!*HM@qd4H3lJocFb5 zqv)3C*9B#t*wbjuNP}Xgr0zQw$*!|uK1wAG^FtvuFWRxCLf_aZSRhx@uOXK&b1^=P zZvUz-xI&(p6%*c*yOfuw$`*Nc+k=>bktz8R1jdMaf4-yk%RU)Q$phZjw%9YDEuZ21 zOxnPG`DrDUkBI@PaEewycA;SBi>mu)G@_Y`se^-X2%En2gFexGizPW~0ujFnFvGMH#uTd2rz)4jGBAWJElE#<_CS+_)%fq}FXsu4R6bZ)y!} z);uV9V(b416(m(B%I!#NRj)ICcNl*k*LbixP3t$nFk~t;u$SI9bGbh7!n;5>M`=ar z7{Chb8<;7Xmd5R_vPz}I>wnpIzF*3z9DT1bO2YQqc*+kSUCtFqGkZ1O}o;o@$(M0+DI4>lDj2)Bo%nWq8T8$XN6xKsRKsiU@r8Btm=BJo*)`?;~f#qX)tqkKS`o?+btk;#(A*K5sfvdt9fqPav)9o88 zx@!%$T**#6S2t^f?Q<;mL%0^%jR~Tdc~hQLkhYVD_!Q3%-jc!U-F`DW=<|BW2%b|K zFYT&xHCAt_!j1}arFAzCNC@NgJ(~YY# zj2#hvE-asTe^wP^Nel%UkB;Mc8?ks01#5I!ojt$vhbX#Yt$y{|-2Ee)v160*&n3#{ z@>d7pWHI*9xgd3{1vIVzZFHI{Syf>;)64KI9Tj6^5TSAbzejhY2-4<<+{Iah22JOy zcYFe-CB~1+*q?q?_w!h2zReFgobj9V)YsxE^9Z6T%HJnvjBr_YbX%4wD92i~QZ9;o z!;;}26B!gjQfDteroOe?g3JBM^qXB36MDGid6XG!npa+2GV^Qe&PH_qL~;xEficXc zCg7O7VQ-EM5(X5~k1TCf&J<&qT9}|VBK5dYji7umxT*`Vl0>1)`%|2QF&V1;ouxWW zuG@QW3aQo>lR%N`Rio-_!t z_cRMacNO~k2H-r4Twjz7n`S#`Jtjg)G@iOmA2NUcJj=KBJ>IGX2-JIW?250R6;%5i z(RGK?+kHRU;(NK;Rn!K!Z4y}$c* zBRHTCS88{moCkiRu%+X2OEjw%#H|HKG>SYT=C2$S*%}`;Hu`XmQn2Ke%E%%-V=>Wf z8B6ZGT)?^LvDx0dK||JOjJi%f{V-XJC-8Mn!Fa$Hz2?Q$%3fxgH|{RWOAf;V$Q4%( z2q-VGBK(GRC2aPLWZh5`LLt~Mu|b2ln@_23@;?6dt&!3U_diu=1K4ye!|~|2umnx# zPlGM|LmmFf5oaUgs3HXFQi|^G z$xJurT%-FF1B=iXFXy|wP=sPUN^)8?8PdXe_9jn!%YNOjex3b+PvMrb zoFyp_SDJoVDO=1dO$0#4YM%}bmt`z1$(at^ep$d_3|jGdV7B=A2&31^{5vNx9Z&Oj z+4VEcuEvpN4@Y+0B!6;paL+NV6+3t4uOfQDX)F%UJ)UNm?dY>Dp|MdL{HKUgUW+3* zxy-$^+XrZz$pDt+fV7Ejh^rK*U&K!Q5?G7H{qS6ImuB+|RpM)8O|ku3F< zjZnLGl^Tw3Ejr^D^1((j(n8%J+n|4Rz*8hc#glgI+Ds+p%%|{+S5`eQQG|sZPl(2T zw`=#NQQ?2|A-yt1R|vj+fivvtb%IAD3raAJmB7$}P0u^`c-vA1IQ#{hC2+;g}hsRfcHXqGR2F2~WKVNy7c>ejJM*KH z*Mq5`>%1suuks^d+r_LMPi@^k z`Kh?R5hZ+b&SyTHRRaX+K%FP(jKQtm65>5^4g~-rab0{%| zK|h2Zm|U-|Kh`=_|W>S4`Oe}UwI`c6xg^(MRv3Hz%aTlp}Dh{+oML2ZH+_{(8ckeEDoQLjB zS)7dC$mm{Zb&ZAv18ec)d8_x3Cf9`ffK6{J{tJHE#0 z8#4~wW&D2kQfU~juv_)|+)Jy5l}aBjO1we{(I+~^S=!fvP$MC#_%>K61?rvHw{ow( z0UOnhvpmMF3&*ZMZxm-)$l?#62L8=zgYPK|^YU^3w~U}m%6eRy_%`$&2}a@ zk=Lg#ECpXcZ}B}$r>waA5Xdc3YE>J+S+LWy*FAtDj>sLDFl|b}Eoy2tr1SLJm!a+q zv$;?ZgnO7}m_)>A>VG28CtVSCk?S*Y3saL+jtfa#y^NjV4!MmAaZ#$+svM#fZ6sq- zSevKn_5N;b04oJcmCqMx&%G)i)N!?skGB!ZbMM+cpG@f#Lex?S z5ecsLd03Q}%lb%)E7ci`;njQdYId_XdspGMbxm5L8#8(<+88!_=D?d#g^Pm%?2v=V z=?;nMEA>l>h^Mw>9qt~4cuzCp+KI}zJm%!9G2Bj{Yg`}0b*l4J<>>ofFX>}2BULt6 zr3Rcx-t7m=`J-jn0tz82Ps4~&pJXz%W<9jq9|2+B#61dD{D6jLTbZ?czkI$E9Yx&y z*2f1BwIhM3hkNgh@^AW*6lgWC#hUJ((0@Pf|SkFk9v)8Jiq7%7k6j>Qm^0U-{i!q_2b`KK#zVs_6fa z;@$l>_N^tc9$YXA-(}IrIVJNBHn~*@MG|G36M+_sgfkySpM$KE*rY@!#Zc(p;2Yo+e*}O!#$iATl?dkw8WeR-K~~4$%N`>y}mIF^fzQSzC3CN zRXVEp&I?fNjJ~|;1&W>ap&!!k`7u9RTKa~Nt5S3q5_9)W43v^Vh#Iz*vwhJCoOns_ z3}CS@h%pCEI_f4^tvsy6+-T5ft=xE`8RGaFM^6RqIveec*pFdRomSx?ia*Fn)rqvr z%jy<)9=(LJth$;~C==7FP}Iyua?=(e328kp#nV4A02j2rMAcrz77e@YvJ9ET z{D5zL5#sl=-G6-QK~SjAtlA`i##cgb{DpX5>SaaR53esJDE_>HFZFUZynqJgvp>s? z+RMPl3poDR)LvA5zkomJMxxePU?k_0|BE73GFa0rcyRB!4p-3QFY*Y#$1D>&H zCp!yS+5HFQ53d)}2(jytJ^3Yc)AKo`4*E#@;U#=ct>+WCI>js88IAcx{?6Zh*~LX2 zeLj081|Fuoy6663W^@Ca@MDbs`*%N%Lw36A);1p(LAM|J%D8jSSNYh599;lrh3uy zW~WO(CZG86@3H=na=UUk70k^Taa{YyA&~TYp!@N~-%+g|-#X7X5?WpG{liAG?G2Ob z?FDk1+(lN0lcjo|g1~3^O6ZQdJ-j1!i||dxhNz;n^wvYVK`-G^*&bYhC)26Pj=xa% zfY`%A-iyktpa^3sI9!HNIkchfxgjJ|tmmz*QQ{d@F#no9xZs6;#YWt1w+s!P6oaB? z2vZZFND`8eG#0X$OER^jGoxYldTQG3yT527M9efrJz2&XKz)?SRcr`KB@90y9upY< zDh*v?N(3awVHlfb1%cqteo7<}zkNVyhY{we@_9@e`Q2@~$(88W9nlW;HY%1mOr%ar z{ZnaIR*O_~u%uQ!24~~3pzKIwqn!CH!bmcl;du6SWgZD+s!VDEfE6zSUtlG(0tlr7 z4qUSq2Jq5wQrkMH8B;?AA`*Kg{sDK=X%(K*M2yj@B#0+d!Dv&#g{vZiz(P419&94E zzM~VH4B-#+=i!=6eK9!?4DNoAKnJubnNX@%TI0pPUDXA zn_ml?;cQ)=Y!fwp=X>RYnIP}O)2~B!;hLfd^Kzt|{__r3A@*(y*@<Z!B(5nKXPSU$3-dmG+r!y}b91wgiH&u-|7v1GZzh8X2u8Io9WE~?N=Fh zLKAlLeVnD59KN8Wk$xZhz?Eb6O06&3S2DjPH~MVX?zarmq%H#eJ5N3A9Lv@h`{<*> zPlNm1_qn$CH$+OjSsb!>eHa;Nh5h_>{{0I~0*QF{STLeYUFp}{eEBZWAU+q(Xg}DV#pZ?cBah5wS4WdJuJ1%NBn_odLXl}+W;YMtt#ujw z6-TuJ$Jb_rBvOmW)Du;cAMa3HqQtbs%V9YFLFMC3#a-_=%g?Unh{a-Y4$n$mik%8< z=bLokI*7Qo(|F*qqx63EuK!}8V~x`S#ogtlj<;}Q!PxH-c+AkqLBF05yJ~mFQd?vs zp{NnYV@-NnK9_9!u-*B?yj4AYX46QujUTfP8bX$gZRpGK#Ut+2!8&lZ0EsN2OL zUQo9G;w5BF`NB9IZR4zBSpeIzn%4|T&&!G7XwcL0*qw^@JNYX90|I$hM^gNDvTtBk z36(f90B0GKiu?vio+qPMysV%+6Ufi2DNdU+XVZ>93! zmC)js-(Ud9ouGV#eUl#kWexaT32$4fIAXy?j~{MqC%DG{A3YMiI`HmEefHww0zr=~ z{y7#}TYNb(LUJWv=(9&;DCEbeIoI0X*1cMUfytj=jiEw~_vr#$IScWuI>1guls~Yo z{c=LYNEY`r{Md^!gRVNmTzK);iAjF2GPh#@5G@vGVBdT9@B z4GoG^SkKta5iJaOe1$j9nQsAwe!B>NI)AY%RsBT(>2~y;bN8m^><7cr-g?+qEhwR? zyiG+zKXGTg5c8l_42dySCOq7rn%QCAw12myY}_!G+l@Iq5|&WH(VkQ?1FA^~#CL<} z+Xp%P(=pKGaMx~sUSOlE&Ba?B`-wlf{2>jD!g+b=<69!LmC;p$Y-t1OasX7^9B8$B z#|QxG=RV#Mm{E*>AfSQ7*qNymvi-!k5Q=P1gW-^6X-kr@QWZ=>jD;m58N}V17jni% zxu=WMZ4OI25{dJivF}WyWtB=Sb`$vYo~@mtCl{iC@demuN7=!=nwCUjW!x*_y4-P< z@hIWm)lnh#2#g2H=KC=Bsa$C}a4`e=Kk_uqsDyJMEmX)I=>6&NbP<8oYf1Qi@J8bU zaCWz4e{N$>v}QmFBeJ8057QdTqJU4PT!Lb?ZR>O9>|N_i^5zeB>h-4rt*MdM5`m}( zHJO3mDWI53kio)O(Ld7!Km4``kAg{7kk6i3Ymo#d#lpv1kTApoJWt%MIOe)`3=s8B zQv){IOv84&{+nKGmkcON9w_st@8L{8yv)qYKb$U;`Zzw&-%T0~+o^pr^TAMq<01y$ zwlM5F<1G5AjUS3zJ*}zVI#MAZO`3N|=#ajfflsyV0f_3BaJ)-`cjryU-_1@-Txe>^ zx?U!57p461JsSlC|6;zb;_4n>f7^{AaTy0rH>poo8H3v2D_j78u49Vw{LvfYUZjfo z7@nwH(#CVc)EGwSv1bF|6#e&}d*m=B8F|IIcN(l*1LQV&b)TYV+zo zzBb{;Fd}F%Mup&a9?II780bI#S0?p~=0G0MA^C^+sc&frGDYxcnp#+Hn9J)I)>Uwz zqusSNUJ9{aG5|k$@CsJ|_&rm4Be61EAeEg!5K-_p2H7asi2Jn0Uk(QbD_jh&ZVEP% z@fu^45I=yLj(^mIb5fy^$F0jC`W*+w6KyTu2;y zg%dRM%P|kQaV8a~0b{g;&gkos{UgEg?YUDOS4U6p{OBC|$&LN-sr#{7l@GM?9vF$m zQDw`HY}LH21;RL|TG3BTK@qKiZ4x;J@$w(s#BDz}fI{QSae z$jcu8+{@Iwh!!2qz8Wxjr|)vG{{_D_SO33L2chZrssBzmJe+esF<^elRP+D(R7o2; z`Mp-byYBVb*_Kvx-=0<>TD^`&U>TCFyCDSYlNmVgNq+9b&QV8#a7N%UN+8B*b z(fqlv8C+lH`n3Z;SSm;bh~{W(_}-dmp(C;A1@6hiHs#xlZ3M{J$$f5R0buEd`|^@~ zRKeRD;WDCh9cVm1GEv_*AI`yiogy-M(>VrQ!tTx#z`e0n= zwMbRoC~j_i1%Y(p3ZUxduMV%^Sp~o)=#+>_7n0fK~#+7RX%0%&{0KX{Be)ijn z=S0J9*>25S!&L#iVTY$v1@00&7OP?|PqqDdw^d;% z9Ly5P*#uV+o3w|gC+2!u^XmRH8igJY-gzEC10knDN(nb6L`B_SdL{)1OFE!)6yL|Z zmnEwFIGW4pIt#xaMm4BlV0K-do{%gGhpH+c2!()JpyToqVh&DbTW(P)#@!kXGjVgB z`>R&@UiGGth$AuoplqEOYF&yY4mg{naG+_3DtmlOt?k9BFUk6mq+H~3lS`{hmE{MCi+7dKLfV|`JNqfi|%}L#8@|pNBYW{18yH zsP>`$GSE+>ifP!3f;mfvh)BZK=goD1$teKl-8zvfhGMR}6_^LSjHhCo$(4vq=Wt0!luU@T)Cq-eVyYVzx8Azul6&A)$66)3h=EKYck4SlmdB)1SVSK@a$ zVgF%%`@*mkkZT>~55ee`l7JD9X1L(;=^Bsz&x8}pGj}B->hoyFXBZ z0MzrQe&FkUelL_36c5fCNG-w6Q~T5K1sJ`c=0JaQ59(t=pK6t3I~H<>mAdH3AP&)6 zoCv%r)(4Ef6j%F@in-&?QzH)sn9z=rnG;`uaR7v{$RoJ=Z2^^2kiVOy&R_@m;`$3= zA@7*{AI3`pjHg1*MSI$z`ej8b{v3szy92Ux;pI%2fXGL;%r<1K_fU^#e8^ z+;ZK9%&?+kZxZ(z1IqaU?Qbk|n;+Eb39j!Q>o>r7q2OMW9lKN)1ADt;#sNctz6Xg1 zJzA;V-gUNPME2C2G(s^9o9lR0(q5zi3sE=>;Jw+JPv>V;dO_sWVL_j{lBVkw-B%YH z^DOE zH?L})OE^_K@eLrUeBkPp=G*4-EX9bh1?*hQ%bwZV?}NH;TyMe0>U@1bQ3O%Ngiy1h zbp{R$Kou#_)jPtF?_L~ZztU%$sx%ehsQ+(!5sh2gjeE}oJ7e4D!9T>4q(7}Y2o=mT zrvuuqSMkfTmi`Ndrt(#Df6b7@`;*c^jyJE$uJS{<#^6!j4n*i$@%-Va{&-7^T%wTh?C9^a$#F7F3yY;9 ziZSZ%AjSjOK4YG!C>;J?aIUfnMvp{%FplTB!aee5D-ADkh?+omk`w>K;Mly!Ylqb) z26(Rd=Lp)(uQWpCa56~QV_TFc1iWs%vxXDXKhOHb&G-Hrm2TJjB)i|`C4b7d&?~h0 zG}fA286&=+Hz>4dHuMu4FOX(2dSF`{Lt&R3!%JRKZc z3M%c=WEOOs){QrRJD`22kRSjcI%zrK=Q>YNJ{97ZGIi`_1o?94_u#l;Wu7Wy*#P)UCft5 zvAJiS50Gt1Gr3r2!6(_f<+Qh`cVhAmy5a(u`&<< zY@CNpU3I7!m{SB?J-ekYjCTb1pejyz45e7ql7~y>u_)-bF#kJ+z7eJ*uiCjubJc{& zNqHAuld>`o@{GIW)s>lk0!U3cqs4XotcXj?qc@VLO5WaMP3GCYRamz9t?azs7tlnD z{j}QV9e>J0DWW13iE#C`BNeEbMYC(0V&7c}N_ZPs{8}}D&y}E$IYaxwc zMeEpq>muP>OY#gG@Z5~pv7?UGx$zK1Mt$D4RM8gD|TGjWv*1f4}jE{V2B}X z8n=rn5^k0_oNjRkm0S)anhGhk>S}9a!%>%C8AT61ywaS82S3VK83(YA@R>z`>%bF( z(Qwj|Y)}1EewA2I^{_qFoc}lTr;GrYWr~{prlVQ9vGEt3L23ND zg#na}9j)V4OaYLP=N?y~h8P~`l5dAmkKS7usX||~(M*GJTK`Rj2j*7;j2OuPA{P9M z0(x^LqAgDJnaOn;B!nwP&yO0=L%$>*^?~~56YU0g8&7or#3LdOPx~#|&6?p--Dfb3 zVAHLc<6z^WTWBPNPv!@`7VdupLw{F^D3TS>*IWtw7oaiBfGBuV$;WDKRLJ3PU3Ss1 zy0gnzm2!5!3at(tGXa@`Y)aVgMaG%x%#RtcT>TdiDs-UhipOdnmOjzj**daR#n{%u zOi`krHW6XSGsrYF_H!jF687x7(jR{xI8ia;+Qo-l9aUr_i34i%iAvpX+y9;L1x+O) z2-?#x2P`Tm_x>KuvwZGU9pW>5_@`Ut3U&ndAOLd!_x033Ix5*c%9e#ZE4kKAq_diD!^S+E6)?^JQ+v52x zt+2$524#pYJnFUcX!qjr^fVvdKRKB%WZN;zNDNqFz+ws$1l2vl)LxL4%C$G^L(T)Z zdc{ZgU7FT2Zr6w;!epsqKpEjbOMh`>Dgff7=ZB+`zncl zdfi@MTz8ZXYKdZqx(|au2BVG2xY7nKQT^uX{f+|he`Qw16iyC|MRD&o-2tV4p z_{iX#zJ2AqHZQV(-id_!Nmx)L{Xw8^0E%HOpYrb6;V}aUeM>k$-`MIRSc2-mCC=$X z!roUfIHERW8sqO)j=|7A=8EPcEND|F$+MdXh(DZ6j66r6bhmS=smqO*x1i5B8s^yG zK@KciI8=c8Y^jV$$~7$l8~&j;Z0Yr&;_#M<7d#_I6l`d5f*;BA(` zBR4Q66O*iTW>n9OJHzk8*pp6%`p$y4tqC0kV&mVOZeLG=fQClyyfnk8Zc9~w{`y~wZ@czaqz*e5Dv@-;T^3x19ZA9{0T z^o3F%>EUzo=dk3Nzb&(`8&nn*$mZ7PJo`@2o4MzP?{u5cu`rJNT94bFb}c1J)Y75)nWNHZYh3n>P@eQMb2MW<=F~X#qg!d%N0d6+O+l-s6fZdJ) zyN5M|y6~aiQ)i8Ll>w&tv_dA7-+~>hhVC+*KIB^zDXa-h8Go$T6%_1J9RY)&qXOS- zzE+(_+YKx~SAnW0ms#-#oG&v-*D$yz=$Nl0#{{YqfArT@hwq-KJ0qY+uVSTIS8b(K zX!NY$?^_H42@EUYfXv9SEE@Fn{o7Y{UckRp$jk{OB4cEIrnxmA%blWkd-2nJgDU3f z>stYI;_`fNxehdG1G!>xq&%6|Qd8?&pcN7um>iA632tkxaBmuD8O1dz3 z&qXmH_UFWdkrhw0mO3{c0QO}G)LAa{!6SH^TGY9Fb%oJpAcRKbQ{`l+#mu3 z=5piB^cmo%zIt84L5*}|rbZx&Z0m@PA2B336{PRfT#t#3{fO`)B7>mXCY4k%B{6jG z!96nK0d15)iOHkR%XN(!b{y)>{1`OJcI+J*WtcW7DB|N7@#i!Ej#=72bZ z+_I3b33yCyPq=jR46!Z3oh4!Y;cbdShExyS<)1X1A@H_L!#2eW&KeEF zpG(M?(2>FYI^9NQ*BmaBw2D07eEMl97e-7DlhB)NIb)U<)OtpdP#-y1;7On}B6#`@ ziO8vAR#z}`3=S121+e^th<>5T`};7@)+HpqW9>XvFQ0yJyW?$uzcIlyeykfCnaGEj z`!f}>@q7YujUCP0qtKJF59r>;Ej`BpT!;k6D)%@%U1@hH7XXVgxb0v-$^US@)#MU4 z?km%N7%{l1V86+dIZ+7G0KyKgl^9b%k#{Ru#Fiys>Tznt8itH*;gj|3Ee3($(o0jiG?p0* z;`}YeU$BLqRe{oWv1OGOn~bg~r{sieeD!yxzRDb=^E#lkuTzL)a7@9kQI{o`lKbfN zwuVG2{>{;x@b&ND-t_qpcD=g|i;Kk>(m9sFRM)evMBVP}WY6C9_d7p+mF}v-b3GnU z+ie*M-H3cA!fe@iJ7xbc9C4EFOTjGULafB z{Wk|MUq1{+Tfjwxk{44agh|zf#fi|@ZWI45BHWW(x!l!j@n|l#FuozlsSGM1pNZkZ z6_mf)`OMw<+nq`zc=gS2fIB>P`Pb|VPTgO>?%(b0O$iK`dRrz4=5YRmaxnD2dR7O; z$b!(w;hV)*$jeV_-XW5YJ4&E?#*Z{_qahi(I|MGsg3Db%wBygN{y4WGqlfUW+4pF5 zRg9%Cv?H!N3z|kvw^aEF!%fZA#Sh;lKOhm;h%ez#OS$+8L)Vxw{o~jzYpQX3!EZIB z+U!#2S*`C&l~2zy7>MM9G=$v0bMY|&J$KpBcubSS9~-;>6ezb$jh0}ZN`|&*50>zm z&Y2|~X@#os>f$^++$-k+=;OXh4uKM53abM6(r1^o|L2j)Th+f(Q$rem#?ya6Mim2k zhcofQmLAhjNW@h~WOE2M4mr>odJNB!H-fu7C3JplNh`!NxA)h^I{yh4z;#Bi~ z4zy1M2p8r&LyhT6NZ2CYTj%?hY$6`GZO^P2a6hweVJJ{9%>uV)qooar$ofK2aG&`O zEV#6QPx*9F6(~qbGp~{8EK_-oUs&6hq~DUmUaLv{tH_#?L{3E@S+%fO73|y zWOb$gObo1V2#BPEENzAz7t*`!U{lp>u=<5!k(aoisfz=%?l=Ypu@=tSQh~OLw3{HKOJs?Az8%|;cY9DT>@*OFs` z_cm}7V;#-^C2_6;2)qfb%H?0Jma<F^-x6T3GKnEjqcywfG;G`0|-l~}F zTS;yx12LjoaX=O;3FhT<;~ibES~IHe5ndYh*9Na}&L@FFu$Xtjz%i!b{M)Jl<+3Xj zxsdEM(OA#0k5$Qh8e>!zc4j9LlV^lz71v-#OH{Fw*4sQdDjSN3MaYy3zA#F({()d% zpmALwAzVrMGQQUODeFOBUPx!3=E99kiQ0Joomj6wJR=(vj?!*J@2t>Ubz zP+h}ETD%z?NvzjK2-f618YFk^Y%6FV_=vcmh_&eso>=CcUQo<`*418cZH*DB_h`SqAWcf0XIr>cZeT8~g7t zwmH7-f!qhThQmWv|5uT4KVu>!g~yB(*!CDA_46RW!rn#uJjHVVz0D(xM=-@B9%K4x zky`nzXf+?2LKG`~ZREJuxf}z~0YBeq)1}T8x@OsMc4cw(OiHmvoMVw$8lfU~Bp1z* zdGNlXf0qRfN^M_lCfofIAP*;l8j$#>+Aqt1W0U5pu88kT1v}qo46NhiUrPMsHz>=2 z06o31anViYP$u+*{pd`m$6S3$hCDwWY{>>8n{hU%0;3C6XBoO#$YJuQp{FOyib4VR z$Arn-kP#hwZWGJTL|^HC&4v3jn zVYus`7b+h`0t5XtUBu#G9E*OFSe)ZES$ymf%RrvdOsjYV6e(K*cb&LQa2_tG7sup( zT0M$m0+H#+%b*UF10pqdcaemfn}wDHLv$MHENUnQ>4#PSn=yNhr3PZZmSSLVmpx!k zm{d=-4+YmQVu{!PZ2`uF?tG{U3$Xyl$L(%e3wMBm*E^>|0%p2C+{?($agUH;X-kvymL z64?0~Bl_U_&*J>sXjlSp<=20T-}$;C%5CFrXz&FpA-OueVpB|bbg%!2$wo;O4;m#9 zf0&ipy&oK2aSNCj@V#*|_`@*uSnl7f3dsR>BiKZKyo|}%hpdyuljz{pyzmihL*PD? z!XZ(4se}VuZG$AQpX_GC$r#jW{?bxw7&jy$5_aeXjblrN6_WObS*=mb9+LXB)RRMOCQk0wux z48wEX7zNksQY|u7`tZk^dw^W+@@&-vDc%AFFL}=HNV8noc&IlRB?inkzAY%zClzjZ zv)H}q7)CEOWuz+!WTLV4%5}rK4ws zf@{-vE~7xU4n2y3N&oqsbV!R_aYk(iat4Sq01E#Uo__I5&F}3mg(>0DFfh(RVr)2p zp`6|wxqzlOAO#s~wxO;jq0Ouxsr2>zupjDwn7ZzGs-wSuZLXb*YjagxBV=Z;%WWAq zA(WY!nU(DAnzs<5xNc=cl#!9W%E+dWtd#5#vYvDG`#sO|kALcQ&iS768Sl^g^FHU6 zZ+I}q_o;ec-&$1@A((!;K-x4M1H)Np6%~8*iK&Z>@v}x;+RfD@BCG(*Pv0NhAL7dR zSec*C@<$oE%hf4jBb7)znDjYnBDp6WO@czF_PPYU5eOrDidIJx3cptzwkffhtLO+VkL0gf)vO9c5iha- zIDj(`yeAT`St@kGn!{`B*MxG~(^+&&56fN=Vg7XiR1huN9Bn8g$c1UDn379QAo+R4 zP7BK)G61vjI>sRc!3p-q z$EZ61CuHV&-0>p0@vSGqRLqzzzh~<6XF^v`T$kD|y80FCUf`HYL42p@%hANTgzWM- zrjt1wn||g}z2HKt;Qqr};UF*Yu|CoL01JewG!8#~9%f<=xQOGU(~l9S6V|axNwK-n z%fD!prAegG0ZdV81RwNUS1Aex;h&b!mL`DhLllx-&Jm!fje-50aNn+smdPV{)CP1a zF`Vv|ak64J(w83jJ~%b@JkC{#YQzd$!J&m4B%m8XFX>(pM;pK3N-Bh#p>>-UiCw^0 z3ZMuv4(EONpLmnS$8y|610+ZfZcPkqSzsry&Bn=6&aOLfUG&U2z@UgMg~}}A&3(sc z$y~U=0|zoMC%!*}AD>yi%WsQ;B8x_f9u5qg!Dt7!#*|7D6#B&p25$lz7gNGZc<0^$ zTD2lTrYA*{nyM&!JtzTK%XN@3w6)(wk+jDGQ}22a6zgBRC`)LKgq^58^yB4P%vsz& z+Ty;sW5inQZ;3}Qm5E(VKgYK@{)|-fNzr9XK%*0k0J55_#cyy-XlHR?8|tD zE(Jn!F@EZLsGYC;I8VOAOPu%a_S8_!NY%tEvENm~aRf9DcJ2!5?dswuz89}dZ@!)@ zJb3WzZ#_gyh7wk}KS>3cBPuRZ+1kBy#UaixXrfS4OB3(R~KDTSie+ceQG@^1n51NhFMHM9BN!GO?DPdgh@*e zxyHe2Gwlid2wiEq$NyQf0{FtHvsciBM|G>kE{b>@`Z)NeAWGB6574%xg4RtEH5W1P z14;qHTc$I;mJdtNdG*I;y|!r7w01CW`#qzk-&Bo|{lnkaExEqj@IMsp|A4m6LfBbW zy=XkojJr(-%;rN>Sc^bbB5brA{{n{qN_xACC|paeMm;&X68@#jDo#G0P3D zCc+>+0}V;qP>5`@!0nV&JkSgN74&zQ7UDoE{_Od(g~H))cQzWw!(IxsNCqarw1-*o z!u*+D(_{A$2xmI7s0eQn;x1VbAP`TVi76annW`mN2g`}WkFNLlr55Jo>n19k*Zng$ z+4DF7#$yCW!ca~V*O;cRX`P8+B6k`)xTZD#kym?I_H^kHVJ+5eiFac^Dr^rpneV<4 z!oYadoaHg^ANZed3AQ?$P0Mz{HtA30GJMcp5H&E6zoeM(QK(GPCjp0#urqAyxwg6% z>8k_nMH?l+l!3F?qQ>Zd)_z&(=11Teta3g01(;nFF{xbHndo!BlVEOYGi1RZKj08} z1q3FQSLLg_-TIH=8%*aJr7+%IpT3GaI#&r}D(3bKLxDwS3q2iy1Ewf|oGeO`(x<;OUDeG8hz&|?bZ25qdDxym=gm$`}8z=!sy6_0TImP^ zxYQQ-h}@RDsKq(!I9JyNLDVnjcq|T)r-{BBmisxVGo?sTustYIhq!9Cvr#yF>lMNF zo*r*49Aax}3>Ubx#j564n_0?EJhWayN+ zW)TYN>BIE{-Ias05u{0oBx!6z8#)jQDn`g4VClDO0_YieRLK{PjY|RqQ9nlB2nOvT zAvK?K^rb(Q62Ny~(~7j-gCk=LT(u3=FD{h68PV1rhEqb>oplMo+rXhgyl^dw!LR~u zBt+d}%6H8I+bbhT!5I%rs|tW5z;b+lEbrsd%qz*WJzu79c}CXRWp<3&R>WXo1Csa> zJss@A$PyZNa|HY^BiID4Wu#SlO&1#x^q9H`QC0cFa@`NhVQ7^U>4ht}oT!bx0^*wv zR!=kmhQ$-(ToKqS&lZd*25rL>&c71CCrH6u$wEfKZ0HWWpxjs++d@6ijnia|g|Bfn zXTYKuFF;v?Yg}-6@8ZsT_RMc$7#5!=SPVG@mbI~A4Z?4Wpw}gMO&5NkahG2* z(d=lf(jp4F;WsF!SVU^!NGRw7H{~xG2lG-ip$9Gllg=&tf=3$$92Vp#SPvvOlAhE} ziyt(Y;WT?GAJkGYR~pF`O9Ak|1EGX676@S=O;~PM5e!6K0lsNL=$F2=O(iI)6->=R zuW`#$zu>10!CyDCkDi(t19=y5~#{#h;KPb|H4#_|=l*3bF6~l?4 zT3*t?Kk|J!ofJoms-o-fo*iZ`r$W}S9)^r|D;l1z~tH~AeYtuj_=SZ^o5 z@a_n;WE;76z$;Pzypo5LyX~i-#LRY>{_v5-2qKDxJ`{3`?q*>9%fBQVp=USz)e+7~ zP8nUqBpMML`!yk~MJrOf=hFXL{>{!5Hy32WWkYIGt3Uf&IMPrhP1F-adpH5+x+AO{ zFx-M3xMWg#M>Gl6a1ZRa}N#mjt&9T*#jQ3s7?iO zOl4w6TLFybE`jq%q!o zAVf(1?YauDRV#bDO-KtE{#$?Z>17h46>QP9+7XSGgbv0#j3!X4YqxcwVvKd5kean0 zb&eNM9sNvcS}8sx;r6MCu+S~7s7qhRK(Kf}l0Qgmql4}1s{iYgt-2m}Td1T$8bcj! zQ#jsgG=lrJ0q#N+6Z`U_#^O$=kbE?@}5lfQT$8OUKEee|q3Nw8N!$qS2yMqih}cUN4k z8B$CtE)UFwU|VsU8+FttPeUk=_CzJaE2$>z8M8w-|GKbFy9;69(Ttl%B|_TTzC@#a zz(&pKf?3;xG3V^6lw)5La3B(#65SQ!-{P^1c&XVkS9@F)9(twac z&RlrUer&7m90pc`fB)Hy0P)Ie0UD)CKVuCBKBCJdedrzw9=Ny>J;SVBFFS)z8On@+ zi39vOmr)xo?QnmM{YhWzD~>7zs`9alm@gtKi(d1Q54FvX8sM-XxxXpBr~xplLW6-gQ#GJ*!cMpD;B0=f2b@FqjED{Dlf&>-vMfkQh4O#= zEGZE-Vdgw$%m~>>TSp((++<~)yy|XqE~vWK71c$#-OeXC@K}W{J&r%9dWA+zkX!x{^ zBK}_}i4DW+Rw6K_0{Ab06P{hF%3s8!P5`pdfS&r1ffPnTO3zf06Ezuo;<|eIMR*oO&UflIQG7+@gn~GJ}<0cG*2Qcax*~ zFDhU1pM8E}f7Y2->l45|3;zJYyeAz@B?;HkfCcpRZCnezXUkw5y8NwgvEzTUl1Y%N z4t8_7BQBZj2qMx+)BWjh2^KsLlc{U%;P~>zC=DNQa3cng>2SNi5d@>I-!w4La&&YH z3=@YBwJWN*Q4ky3^#v|Wt$u_Pb9X16$hk!e%hOtxzm#man^+nF>wGWK}}q7wUmLu z9TglxU@zbz#z@&0rX(!{&{Zs{AS#o+t}$>9;88g~q`h=}0!+>b%R;tfcI+z+^1NGJ zr&bK(3_$FznYtw7@i1pO>dT`7v6ac&=Me6;AUbc#Q9?x!Zem*3I`WeB#_HW)pqXi6 zm?yq&-Xn~UV&FHh`gy`RmzvRrDj1mCPJz#M!3z^X)a>VD&M&`aAMmWivZN0VslZUp z#EF)78)=@~k0-%=7Y!jbXzL6SJ1L|6OE=X(*w*+z#4Tr?n|nJ_`*k5&pxdikFe>F! z3wKFFef?voi6QVkx3gn@Q@ZFPra{hx!eDin*Fej;uRO@()srKJXAi(@jpK>|!7&3$XejMRyV#(lK&@Dm*kB%lkDu)r;$hL^~D`#r@QF#AbG3<4$1 zM2wxPjg4oQ7y&x~@Q${=HrCA3<_1S+CXPisnI)=JVya6Qq_)pvF>39D<5K2Z!rOCi zhIx=iwzQAnk^Ja|=TC$JnRaA|Q-iI~#V#enXd9Rl;7)tJIqWk7Xu<-HRD1eOfWk;GB4nrzE2g%XRgtfvjxEcEMB$Z|JUIR1SEhc%!r2GlW%N zX*P1avCzf+`|_}~ET8#W|FwAgvqVrTHYADj8K}C9Kol{OQQW+Xf=a`~ ze!V%GT4B9pCWk@eBh9(0&Cej)MqD!l^GbEG35K2Vf;vzO%LYRj(%$~1=f>y=ARhqF4u%&P~*c}VJmp|bpBWSn<$LK)ucg}*+`T0Wx;*Cvi zZdRl=-QXwg1YBmcU=*t$*msD+dCV{X?f1Y%@3)UEQBs6bt*@h!)AIJe_v_h^0E2CQ z@DW}+&Ry|rc`J(9ds`KO`O`!r{HD=(_sy-}k&Ix9Z?^FBL=TCPGDvaNOMvMq&E%iI z8B>NM*J%m0v>~Xk)@_vc_U7DBsbXIrSg9z{NC@>qpq#S(Z%ws5nOzj=i2FW$l+3gy z=DW@5hl2V{`4S5Jcu~ima)>DFJ^q8YK5FvJHDJU3dExDBHlPinE97ah&%)vPF{Yj^ zfA{CVUb2XbuM$Lk5Ykb&UZb!v`vWPg!>zurFdzGY-dNqQ zy$mP|;03iKTu4$TW+~qmGC@?*Q^BZ9XFio!IcYi(gk@wDr~~(I9O#;yh5ziW7=BJ4H8tiMD&mU$K-|zG zq+M#_i)Q91dN2(Dk~e{x0@gBP&kc@Tx|X=88iHl+1jw5yh{ZHTRPbCH92x>(>zOLq24+ZoUT>V`B^G;lc&TULEMIbPlA48Yc2cef%@p(8|%HY!y8d z{Qy=u+jjWf@X&vc8nW0Cr#be-Z64(B9(%T89jtxzd`5pRr+G>nKeE{66$OwiXc{ia;sBOFMogFLOv1^L?xp0_(CXj%HAw(DFpEXHzT5r zCLYfgub^K#1M59sdTd5!GE2rE<#W)0N(%qIIFOGxE;rG+*By>=VeZ&w)M*oEb2i)j<_sGT7G}b3j8pNz|JYLSZ_mdy@bfK?$^825Mux{v|cn(YuL8R@*?q>BAuaMY| z4i-#U=+i<~_HH2}FT9JEoFIL8|C;tZYH;hb+DYO}o`59AK(qpZA!m)kwUmI;1Az8X zw6%qj>&c!WRZo5aOo-vUUrU_HY~+h)XlwF=T)vPO=Wv>`RqwOH3#k5+&<#(AqlZ`# za*eGCj`SdR<818hIrr9InQ|)GyYQk!?;Oe%vCl=m_=X-R62IhYas%Myw-OWEZ*;YD zIzbITe|wNDh9M|lf}64ltx+=9_J2H91mDd?DU4APY?f=f16? z$-?}VtDC!^>LLHj@R|u=`1wn0nwaTQTl70BJ@p4imFb7Ilbagzu0*cu+u6&iC-QWy z6AWG7{ao<{CLS3fpsx$PzXpk{pnUHb@SqM6g%?)f?D?KQ z;RI5T+5T*Gmd

=nOTijE!73mtXYwyI~?F3OA@AhY2Qq=|N~ux0Rv?mc%dZ+}meD zv4lHTERUVX|FI^5g7Y6?3+@HZYzeU83z`UfCCpiJ%XYK?b(6939T*ZZBWYu9j@sSv zCNNQC*fN{wK*_bKxeBA7=VJ&8FH66ZC5&Y2l2jbGuaz!3WEXV#&A|GCHyfLdd*ndz z0LkbTTg|#UkR*PoHZvOdB?TY3hR8#{A*Q^-;L?{s<8zuKAEg>h%VU1g0qf2I*~0GD zH&*b+O$5Ww-;yBAx;7_MngnBh;fk|a`pWelKI!1%XkYikP*QLBywDki-St-k5`U#K z8t8Km*L!^LeFVI&^cmtVGymIVWL|?i1OhhM`~%LWSw1{yNoQc91YPd?kY@mW_M}Qj zFsck^Lp)U!Hm_OZ+PP|vs*sT0&g!{#iMdFX*&G!05zG6AMRYHk=)dCkwU*uX4c=*> z-}Z^~X*0AFE%f@nI;aQ@4*owUs2fIr>GThOm-jmsKy+Wka*YS| zdb_RI)yhpUiFOcSUs{skS=(WgQ7_t>E}{DF)g)Q<8)qU|s{ei?YwMLn4gznRn$qF<&w_*LvWk=_bc zyZUdnb)*!4!QKnJXj9%h7{fHu3kt$e01h_bgWl)qZ}rjFEdwJU$iit)+l3f?`)?|F+2ghsHy>izc$T>nq0$ z&3Hl*SQbnHxSIL+7B~B1J`Ha$u!_#(G`F~}F^@PsTO%n0P_qnk0J!m;u{D-%q~0CO z>g@<8@~}ROd{QKh&v7l*peF$kGf3MiTf!IL1oQlA)o1-sVv)V4(9am^iRW}WzGg^3 zQ*|;8yxq4&Up2YmD0stlYSY?J_8&43KiP@vQa!cRB2Hn54s?mm)3yeHI1uis1*2%e z?u_T?HY*GSjP_p>gm*;0{_ZtBUpfLyE;0wi(@z2T=T54S789| z!W;F%yBky)-ERB+$&G{QH&m}V67AmObZ_iL|LqMRaU#FBhP&I1(eP;ixwP^(KqDDa ztY1~(16jY}x6=B8(Lrh83k9j%(gk;EJsG|Fcd<=WYCZ0|kd*1oa`}eTM$1?F`vnf& zF~V6)+W8A(>e>sZsNnI+KYJWzL56M$fm_lPS*037mERI!Po1pJE`LH>Cq?p?y2&4M z_W~yA0W5(f=Z3;#Qiz-#1s^@PNZo?q*`0;zRd1Wnm#1aymxGLGY5+TADGaGjC%ADt z43uZNeFgHE)TdWL3E{2_ZK}kP2G^X!&2}|w?SmLw?RV(dtPJgl>wEm;v%20{XSaP2 zcG9Od1@<+osGf~#{R;;C{|v@27cd+J(q^nkXpB8+0<3f(9F4nnzT6=Y5mM(JuYO6V zj1h!SD_;NC&e`Ke9iH~{3A+CIQ28+BFLLqY8=nIf5?dn08aZI108;Xk3|VtM26MjLwd~nZUAQ z=+>?K;)bf?hlPk@WNd9bk->P%$p8cK%11{Kho7Y3dl8NuGzIkvV2!=iFx0gq0){6( z@|;L$T09F|N8F#cRe>2t`I6x^Z=`&y1MTkoT`J8)lwdwXt`DWcMPkhoPRGoG{u>jt zIs^c9{fS9#NPV0!@@O?4mLJ4~`I4jyws4hYO{~RlX1G+G4;)a-agT4iI3MI|!$Pa% z%`TgQ*&vWNouPO+D`M(+`H~FKwHi4B|E(z}YC|;FXLNKr&`WZMs+R2sI~D|V(P{!r z-5e41^J$kmz3}$i+Bk{!&r*5{=wIoKkh|4^pnLY#MHU6J8cpw?bjH4y{LVb5zTtfN z-%)|;u@r6nm-Thz`MkEZJbgLQZ^^h86*C^9PuC&ZyO+-2nN+4|k6q;LRG5Je9&(VY z?g=DB2#LDwLww)7EUOCib`E`MU3543+}#3xXZnAm-}*N?D9s=qLJE_A&|$fZ>)ott zi!%FYsWW}9M;=x{Lqpj+EYebd5OQi(+JL`9fh?~fP6x)i>-I$vZ+@HuBJK=5EZ5Z0F#2kQ+9ZyMnYp%+BvwA)0Vp@oW zlF1FoP7KuTfdB1(nqbNWuK&EVP#)8kMxE~NZZjThqC67;2F{9ukp&Ih4nweUx7%1j z)Gz3vpXjGO6uy*@BhH6qmZ)3MQagqMf~ned%-;0?^o#St3n)(Mv%-@99Tkofc-{Gk z`d-OGh-LcHFLWM9Xp!H+qkArAF+FuGDskt>C-RPisQdqShh`*cX zNCT;>4um&1Q~?_RoBwSe2KM-0(7G}4&uj%tdPt5X6S`7L4!CdvZI8^%1t~~vR@>iQ zH3i-1cy+YPvqYFsGH)l2innLF!SgsqV!D9Z9VppBj-k)Ix{?xg9e>3<8eq%xeB0{~W^ zb+C_hlWpyt-H-nyKJE5Dnf-EG8u>ThFfxr_FzV{%EeC#~Gm;0o*5vm?s=8hOFT625 z>8oD(tAKu7;F)EAnt=^ENl$%p2oNrp&j?15-2@#cP)kZTB$l1g4v_(iXjy4fieJC2 zQ0daGTSJod!d&$&m0m@VEJc$>mUiMlGfbj9U2O~w|G+I7_5&?k-TR}#41j8{gVEB{ zcvB9-@1K6Qyppf^?LrFLnG>ecLS*t~pG-fBmd_f5ygIVTyZbk68^;KF;|5E(|)V3uGl)grLBEuC{3MY9s$~|T8cT=gxsnkc}zwyMclfu@$^HU zhzPQ~$pUG2YhEEJj6kmAht{OAy3IV)SmFEJSZJJGCW-OCAqa-`zSm9FzsG-_ zgp_>1@nDD9=c#oDF=6lySAt7^PbVe-%3w~^hPqCBPTtChQR4y@oNoe(cs9?Q1b;Km z*4GtV530F@#6+vzt)1@?X(@^CW~t>wiG?+j z+N_qZn=|tU&8~d&KBxI@c;_@DFUE3pGd=eFnLkv;*NQf5Ift_`$(CH5b)DvcQ&9@M ze9JVubKB3FKuu1X!3p+zJ$7&e#`V?)m_)TE1(nkolG7&tk1;;bvPDfQ3W%Mno=2~FD*v}B`FgkK9aZ-oLuI~~Hr z5UtFGd}~gl9Ze-QAy4w$*~a{;&p}a9Crxub9};5wx}0c^1MJX66O70CC_kgGn;Qd7 z0?VK8X$_o#6vaTTH<`9=B|KBk8&aKmNOJ!Feocz;537WpVOAuj)>M|*? z>lG%^-_>U8h6dGX=GQ%I+`Yy;32D)eUSMK}pa0h+)l8y2&BMm|IGcs#I@V-?L>+_* zEAnC-Ii5@l%toE1y2tOUY%~mv$zG=4fFR71{e>^_BE~;fCWO)pLEOzN;W-02vW%|Nb2^I_5s+Pl-5KQi-mR#K4Y^#fCiq zcqxsC5qot;kmsof`m#)^X;m@UL4}QH<&pP)s7!#F9SNp2LGiejxz{5wd{&{NHj76e z|8*9#FB%}WPYs()v?K}fzbp_;9LerJ&_ z+-{)Z)=VtsRFW8BO`rjA9aMA^fVR8V*n;+a?&kP&cXy#BQa_wyQ>$w^Fi_)GbH>H- zM+SySy$p3N&lVdUGRe+xrYFCZ6f0#grkyF^%&yivRt^2D88t-ZWCj=M`UNtA@yNe+ zxn?Q#KT8nAX-@cYn~TcNeC`m{ff51axh?lCGeQ@fGmwcnl~rAqAKg-lCXwM2Q59Wl zeGmIM?RGP}Ypa_$olHJp7fjryH7{niJ=>rGT)gLen3i(%a0Dj}>(II_9KlAIWU_e0 zI9TD4d;U_|OODgHHkSoTwPe`CSAY03uLz`F@!J>qDEgmZWReKeKq0x1XEn4%o)+%a zyPXo{wx5p9t=vRV^qUs!y{>08^ju7RoZd+jZy7Dc7M;;E%8Hbmn?Rp`tQ=jTYedWX z>pR@YlHi!~Ib-;w8|`Yevald-u(td4+E{h;)#(p%iqilxi**KtN~D5cc}bv^~fbXU>#I zBT!<60w0v0SpK?EFz~NSHYeC#mHvso2exLJpNJ+gVq{&IYx6aqi;U__d31Y}|GGx1 z75V+J!Cw(FVL1lPmssb|M_XSc7QYFi|8T{*voxdSEg;p9hU9O~?+h9Y^eR}-ND=Iw0KaaaePtn!9%}ht6D*~Nsjr}Cwm!zT%hd&@ z&7T|mWYG$ipL)2aAOA!Ubv$lZ{{62JSvVvk=r{{U+7*R$&^+jOK!;}5xy#QImy1!E zR6HG0@3c@+DP@2)t)dP6du%NgdVt3WmGq3rDi2{{eiwpFVFO}!l3;bIr7G=;3xZ0EQK!5B{1@1wXQ;<{^f2+tQ2S^KmSce zVZe>FDZdVAv$_ENJxPRCsM_Rx9DZ2@+GI>n;Qu4&7^|+BC@!7I$3Yt_Ff^ioTYO^8 z4KFx|WaQQQI`JtA+ujs92YkhUlj;)lDHZRJIE4`pKn2+{{XE?sfHXu;?1vJe93x*= ziWHzS!cE8t%)61PYp+|sfq!g|v%APHv`wKdxz-tXki2G`E!_W;hA#?7`dy0fp@Wlv zoW3m%W!2*&IL&wjf* z6UhU*uO6Pq7;$EBFb8HZAKaH8bh?MUbtw6kK_JcNdUjdG66mpDzb*XH$VzW9Afet3 zd7UH_VgS@xpr76T?%y(4{_8Pil|S~;hTvIFVZF1D#|O{s83yqFFr~Ivk4!PT%_6j! zr7)8(gIR|Uej6#$$kL-`&BA?GzwXR+3Vb%ab3xA&+uTe79IOdCk#6ucOr-XK zG7^%}&zW_@niEkSYH;g65FD*f4z=G%hV$Z|Yr8H4C^^)op!mJ%>dfSro{uk$4+JyG4ZI0dMN50w4P zV)(73?$fTpe?z=9@RE9_k&)277ta9B0-v?%Oh5RVO@t_Dc@0!VNtrhW&;<~f$k6WzPPzRt#i zZ>1bUV#b7i2RxwsB3};_cDr$acAkcG7Voo#YDDtak3*xMi zI?U?Yc8wgSNum`_TRk7iSgnoiF&Rve=&D>p(<8YFx8Ne7OVT3I|GEJwI3J4w;hY=R zyW7c{FUmDTAsXH@(;P-bjU29e8#s}#E_UImD60Dx2eN>NGY4h9*P~w8|n$ zp|cd7kJ5)eq75(U&AUy+v811hD_7QgjI-BgqHWRgC!4%KERW!S9lW(0My6M~H)KSO zy5h*SWo<=`gmoqdbW=%{UWJ&JlQONII6lwo?l)3P7T*D#D$q9m1*lXQ=rWsHHuj=5 zTtWDNK!UtE%L&m4Uakwi}}bPm?Ii;2FkocvGIlCP1TJ)e8~+p?O1~f?c*RlRs1misgt7)e&zuy z1S|ky2urzEv-KOo%)Bx>6h>Ocjto@gC?B_%mw2qK^MCmnE_l%h2&2?x&NwMxV&iv# z77-HS@?>TriA5dob`WshLx8}NBIsdZnQsVEyNiok)vrPxFddytS*7V3C;^o4P6c3}@~M3YthsDwcNEmIb+lWpU*{Yt$s6 z@jR|}7d*9M?|;63e+2fzbGF}-XKn+}FxK^v&$z&2^CRC2GoLfm$>Khx|7pZh=Y`m1 zhvYwzlCGp8BO}|NIN0sA3cM#4axnT=@dtbM!+O4&Cx5<6_y6I3ec&l1-TiZj1?67H z6+biD(H9^8I;-8edBr(_D#rTSS0zp_lk9%lDj#otJ=nz#P08p8CV33gmFKwX(5U(|bV^5;fKcu!uZ--o025)`EA z_#wOBhc&aG@Z%efC#BV*e2uga>cA}tv%s{HnJ1J2@iSljUbnELTNkVOSPE6D=A7)_ z{?l%ng^CJ`e7^!+V*4GL9Pr~*lG+}Ni=LkR63=A>1EPzzqcoPC*90axjJkRxM`1Ai z-MPpwISM5Hzu|)cF%G1Fu_7l8t77OEQ`Uo7WqZ__k;zU4Zt51=>ywiB@|k~f<)3OM zK3DmzS=|uGBYom!pWwfV^ND)FNMd8*N+fs-0{mw@5d8OVFP)^6vLZz~XmUkCVZx*3 z{71A@btZpcCUew~5R~UJLFIVoxUp|Oq)%anr&1GD5|*W>x}R?}bD6)F*W8(cwy)$T zQATpJCL9pbv~Xc(D?+Z@8ToV|ndick0RSHAAvtUW9`q6F{~DIzOLL3NMr`h{Ejp|t z+QF@(dO}tG{*L>T&Ca;ZHU{@1?@cO$AU#x#0f~YiFml$;bTbh!#~VkL>(WGwp&TC8 zLJ1Prd6#aY-1a~U$ZbKxzmKerMF@JUGo|(@GFd0ufpmo{_m+RQa1)DCed)kswPkKY zk!^iV3&rVyq23#jxCy1WrYj*ZkO8Y9T&hv06X^ng0ZPk*ziM6 zbl#wqb#J*YW8n}kn-UGac|ySZp&nuqtuwXYPs5;j%d5*HyGX7Rc|K|9z!N_Z~| z%F5=FgmNnT&K>{tpS*UHnpgTOgjeIrl<}G&A!ej5!zezPU0fv`1{qy*Lf zzv@e{$57b-ZDi=%&Q!DPV2eW3neddhNqNaEm4=Gtt!~b?gS>Fvr))zqWaZ+=Y66H& zQc5hP6efkmPCuALXIgzli4-o4QOLS*tl|WEH63w`eL<1?$1({jN2OR6ws)VYf)tnH z&;nDF;r_qew35Zyk#1rVb4Oba-QP|Q&DR!zA!?)@sTN82I)t2h>W) zG&Y>y>R%`VI+)X_EE7ju18}~70cw9D4bi@pta1y8 zDtk7VDr{{_L2t%Zj2xoEgA83NMnV_$=p+(tH%0&GrwV)uUebr;E*D{2Gp{E&*r;%b zhUT~m(6RN_-Iq5!(9_nQ_osu2gVu_kRl-V)-2LG{>B(j|o0D%&+J6!2`(7uG7ubcw zezYB-XD}TAcXv@aHBXVbMfp<>w%E7cN7@U$TyGN;!hZWR>VC+1vbU_iRh_Kj_qNc5 z@a=`#Hey?aO4RM7j78L@f#%+xjxw0Pudf_Z&wAk$?}vrq!40P_XtIlTWT6 zuf!ZL!AV1kD`w9WcHT6@NlA&7vnKEh6|y3)P}!RWs9^jTA{ikmpWjSy zKCAirwa*g|phm`Feh!P$75%^CU%z!s9{Pxt8a>z792V=qcChx9|1_?Ec+HTiPZ-|@ zbt)MJ4yf!a3`@{B^m)(Kzy+rT?Ghs-(UEUX|18afec(m*q%h9r5Ef$`+>Z5k%eFtd z>`!#w84t42t(-&0DTbBfWwXy*2pzr04j4KBVZkjEM`^IdS<4?K=93ZPi7f1C9IxXw z5;&0D*VkUJUv?OLe}C5vT>0pKh->-XDt&dXEic4}F04@^#HMq(4aTsd6zX{PQ3w}^ z-ddtI6c7tqp4RKrOu;k1B@Ti`jk~V$X$5RO?Y&*mnid^DnLK6gV_18eT>VQZPOmst z=p9d;oEI-86#oYo`8C3!U&CiBI8Bi%!h}Fr5PnP#x+M&7C;ZZLnEg(~tKGx+` zN${7@o3fkkV~O6Yy3!+Qzwv!Qtnp^aj@ttSNe1FUJ(wRijMU0ITp0v9N*{uxkY;~U z;z&b&#Dly3=Tn|u#Rbi{4aD()21pbLD+Q0sNyll}Lgn=+3!gl$iZ`;&SUTeKGd7d7 z^QR)CsMLDXP9g*@ROSw%rDSAcsrbe-X^4GTD|tQBjs%$fa3X$$4Jhe?EE`>t1t{ue zmAB^JgovJO19S6C2xfn(mf1|EV>|Y>FlI1eC2Yzr2Ae? zaec0PbPl}iKx%dGVc`?7XK-*1H=MHHd+l(J>M~3yMpt;>X`eEstCsVPb{YkGclC$% zgFB$T)G9r8yiIB|_k`bSH;yL}+-Z8{a`QFBm(uksJ==%(;)FBR(eYkIC7*KpYU^qt z{OrPbeSNt@79)YP;Wz?3A!qpwl$++9_HR3-~lRw!cL2VIDI3T*IX zRK!j7_&mgFeUy25f6akExPIW#;tx;4JmpRs)=Wz-EXRr@cj*^@`kiSujGohb$sRE~ zsmX<6M78N{MS6%qdWYoRCVW{?|f9%3q1rAYaZR%HSX;^(>C0;6rUoi>pA%UGYm2JfoQhxM|cXu@h4{ zf+edtFj8YK92F_IuWpty@MZ=dqxnmH6x_$@xf!?XMJUY8BOYa#t!m7-_e_47I%Y~H)KgG6bfvtCj# zCJf&V2hu4Zqh-^sL@g>Cv{Xdg-o&y(l2OI_Ge`P z!L}_LXlV^(6UbJKj=htyU*eG5U;Q9N9hDq#b}muVpMnqb=tqz1uoIf~dAJmCmG*%fJQK289q@r&^T_0jQkrrsnQsiZ}UpKIyL;r_4Z@U_`ACPRQgxubF6 zSp%Pdcitp)72SHxHd)oWf@`4xQE5?+d;duYBt!G|Y3G1sT>-O155}=UCa}}7&-;SI z{??>EqYm~j*0+s@RuFZ+R#y4`t|$I^%*j1Vt$*Jk+ZQ*XdBt;tq6V;<#8|6fRDvcM zSHgt_XaPa{ivcvQk08}ppV~OpjccLX=l^!u*X}}8&Ybqsfw&P^dGGaT=w`i6Rg`J5 z*fJ$;uD=Vl!HF|1t;y|_8-V|LKn5=20yxH#14Q~)a6o#@JtZCfBzd`YbIR2sc-J+- z!S^_?AB&zDWl<%4%gDHPDO6u|Pl0WuZm(`qson@Ie-B?PDrx-=b01e7zJ_HW)m$Nql(8$WgqTqi{Dt= zc$s*Q7HI^Rc)t`ri46Px01&N&7wngM~%cF<9&;!M5-Q=9v9f98`}Y0K7$t;LO3)BDr8`nnUG z$O|Dy=KIg9MfG6L3(iV;E+3 zLl&QZXZfs3r2#7|D~oO1uXCR@asLp7o3U2jZ@WxQx*oxI^8OqjqoJrwoj7^uN*Y_# zl~xK!X)S-}Y3{9=U{@cRdS62dL4m7E`|;p!GZn){%yzC@8x17oO+CG!B3-_F?$Xg{ zJAZD^ykOKBgR+n{nbpY;@hf(u!O!^~x8?((w6!?R1My!=w&PDktN4f_O%%dejL42N~OSd3({a(nrnp zugCFXnENrR`wh6LO#z~gQT1$O`^oVxPGvtT8qxmkql)RB+kg*(gdYAW`n`xj(>|5# z@DkM|MEy;&DzO8vcr$Y~rZ%ctzG{M@;@p`ZA@?**W!)f#eq(_-7u5dvhA|EffaRzBs%G$ugE5f+dYc-TA9< za-WhO;q_Ptq27Lw&^P|Dw58F({58+?1-o1iaOvr-x00UeQXFhxrq$ocK=NP7ZDLKN|9MZI32Q$4%QuCc69SKb+$W>E~&f!RbfoM)SrkWyxChpeximrX4v{((gT1N!_MvDW)W`yhD7; ztz`KRr3Taz8q}%r{QS7$X>Y`P+jwR-iLk4Z)!&*5Pr7lj=i7o;N9wAuDN_$@Jp~Ebl1l=dOivPBS`@I zz~`T1z}=p`fzQEMzT<77ShD_C`1Q*d84|D0Z6zxw3pph7&zt0OP-<%s&CKgJWpLn( zYj&1WV#4SolJlrpRk?D_I`GHOAq5%L#L(p!Vd{Q59`M^ZZTc4)BA$mFs-DR-8ki#| z@&D5#xHlN5Z{uY}esl#Mktb~9e5R4}0pw(6Wo_=y;l+dliJwA$V>UALKYwr6O12S( zfykMH;&>!HYk!YNt?p1Ycw^%rmB%c^t#n>S)Jw zl&31Js%C8CxBmFP`<(gO2_hs&^>Rl%_}4Y%V?@&Gm*k3clyXj+uVR$n8_TB6DWAh9 zZw^)EW}m))Uz@@R%g2$_`|nBBZ}-oQD=AQFFjgNXlM{Gr1E$BUeR+9QNPTU1Q^%Q>@T89)FLSE~!fkDBV})kXXTAQ1rf-a{ z^LxUL+PJZ8Hnwd$jcwbuZL6^w8z)B7w6SfQ_x=6vz31y$XRWjM%$|8>=9w8C0aNAR zI=o1U63>V63Y68g;kA34r+@XEBGlN!*AWTZl~nnmz{UjccU%FUfNv`FAyHU_0|5_b zSXVdODO`TLEdJiddTUXm$lsuxJbf_>czjWj;%B$)oq=v*gP?NG*5pCPS4Zaun2%!@ zgJCHH!3~}E$WsqzRj|0PpIdA=N?vB^?ZHt0@ek>7ZY!79qIE0 zTycFo9nTv191(8#zkPy(9sSR?S9%9JQx;d~SxNg$e0 z@ZIV^8^ycGD1<6L6)(3{5OCt*WatXl*Zl@Apw%90$`P`>4cqOz2TQ-H2h8Cx^n2B} z$AJL@9gaHiy`lHMtXU+ft9Nq-zyhx()E+w%7auhKE_u~u@WBs71%2K2c_C>0?(Vnh zIU!w|{B$uJ5M1&~)IZ?&dc9L?=1s;STz&<0+?c9BT0T3oPij7m-mp(#Frd*t0Pd; z)9P~p<;Pk5>FfQ|PS#3c8HrGj$!Q0isG}qsHc6FHp(6>PZM%N~Z7cX738jh$sFF$r z!C2pBMUbIkw({!6=TH21E!45#KIQK zi--3#gVdK$@P2~@faA#G$WcYU=%j6w*tpo8;YP`;xn~y`2k_bQk?YDK#hr;4#J5Yq zS4xKZ?|b!R#i54Tl)ZOHRM-1d`U7h(h_+?8IVnsi1cOvWzWB{UXip!@oL2#T&w6Vc zz0ktQOv{47fU;=6ZI~1c9wzWd80hh*1mr3vH&g^b5z*@p_I>Pc9%?d$u4h-(|zwLUuSXO^!J3bVuuIBxAnv}LMqC|#vE7ijW5=t&LGg>VLJ?(2o$o* z`kyuaSS0ERPg^3$EQggwZ*+Z3d9q-9M+p*vv1N1fIMe{j$oq+L=ojyPxti!aUC7p zw)VEftsPMTPuoZht*zmLZy}7kX&DA1Y1Nw78^=gjryiRF1CY@FnYaHUHed~g9sTAM zsBHTD`;>y>(A$|sqyHht$8|=Zkb>6sKd(gB*ZeaB^#0zYQXJ9!c~XK z><$_dU$lQ&{kG6`{}CHu_EJPncF?(TpQZGp*E+JPxtrD;)_0q_tJP1Svd5&}&(9e)`88Sl-N6Yr{JfQfsG#k& zPn+cg3nT%E>EBnkF_*gsJ$Y&0I*qn`EH?Tr;`!s|q^<>53Iwj0D4``B?VoWs^7=9p z(7+Ps)Vg^CP!gsINB;AVgg}qCp!YNWRLGxSHbf4u67Cm^oJw=(X?E??y zc>dz{HiQ&le9ChM%!mOJq?azTxnp!$tPQ^!!#;Npi45scM=Z%hmy`UTD2_jLBXPz= zcRM=Znqs$ugkzBs4v2Dq_G*jWZx^8GfXgavjB7E7V(RTri_4zfJ-*AKnakU5vy+Rn znFk1ZZz>^FWGPs3ahXzT8I3aX$J`v>XtdYlBbga0Nhbz{i;EQZMibs=v2?$50#Ncl zieyyzsw61kKrt$BZTi;7bt?y-iv$mIck@$Q@CL1J1ON2Qn^rFi_d~zl+4@isO0XoU z(Au2$$th2Xn~gn%?r_Ux@9aA>VN%qJMxODwq%yrb4vob>$v<~pAI&;PC;IOA%eYou z(q{c`6{8bCqA2}DXGn7KGo72)ws4AGp>Aj-P)&mJoSaW7cT9*lArkz<1BhMBZUi)M zF9h+&c{laQh%%=ElP)`g2H3^$!y;LBdxD>Bcvw`3^ z-fk5pi*mP8`ej7YvZ}VEZ0<98qt}mD+D2OGZ`u|iD_YnmWt=bRbex7x!6uz+?WE1g=XnHBVgRr;ZpQpg*b9R$hb*LnQ{y|x)L<%a_m=a5aC9NHS(w|@&XU6L$5o85C)gsO;$*K;yYYWEKibI(rGsfv=|w2Cuzb#cyq~$jV(rMC~&<*Q+I7!kv$k z`@bj52=bC}L3quPl0)RuqyT@_gmYb&z7=hH8ME?i%0%_2F?!IIB7q8wb+HpV6C1aW z&ve~3xa}g1PYuTpc_~h=1}CbnRnBSpU>YcD(AFL`_vlC>PvVe`^i~UbBEQKbDu!E& zn`QQh$tBOQ=<8;Xh|v*Gr^ZJM2M33QA4?R+_iPGc;;jXhL`?Xy*!KH#Fn9@l^i2N& zfnA7Ra#|CfHXZx5^EJ2T-L|4K_dvz6kh`*m-~IkHYNU``8yFCiWp(yuo6SN>HQ*4^ zjSuZQ`%qx+-*(Szv{t`0)pCzp6nJHppKxWoM0o95b3*RY{7Dbl_2TR9hzrSCks7Bl zQc~5EA7i^t9aN1TS>bt+44)texk43MCA(4%#R&RF=%Mi z%_3B}JTQ6)p~B0zJqhCvr#fTLd03%B(=Uget4>*{9CS(Trr$qw@y-UaDY?4MBvdUs z!;yo5Opnv`1O@#ht-zx0rj(yu@<5W&iA{>Bs?~%2>df}8!*?qKaBy(CNnaYWn@UCD z4XTN4LXnh=7*t4FESzR1-u)4o(h4a0pl;tj49Fv1ZbyB%0mIh|F{0yoPi?z~>Zbip zM$O)7?hg*dQA@j!o>$t93u8c4aY+)P#(Z9m*6;Y0kTH$& zr}*O1Ij}BeWR$3zTEmKt#ip)mCe`_Ha66N2Jrvr%6(l-*T*s9|9~y8G7lz7|_WQCFqJk?O z_kY@Ndq2uQKnIf=l0Zm1JvL+RiGeQ%q!F}`$jR@PHEZHvD`t#GH5AROpix=lg1Mf+ zvXum-55B0VV8mc$FiJ%)j~zI#on4swz4CC_t!YtGi#g!-aK`x?pw;@cGUdy&=Hd?B zr)w}dvGET$TIXg<<&IR5W4$`0@)N;}TUJ~3JD=gO(_#)SjJSzSGYR&3=AMf3?{Pf* z={o1`&p_ktBrI+1O;`Aufw6GnO&Ee^@@rvX{)g&p&U}7`NJC3yUZPPd{{}0E*viBo z{Z%P9t^@e!OjsJhWZ{%#)0*rCBbMZBL+5}k>$Iy(K8Ww(&;IULPKe$d-W zmf?l%+)EKNoygef}KzCp%77svVjqrj7mF3#D3%jT1b1Z#@yilXwt-e=EE)S*xija>f8n>?W!5(=}3 z6uI#a*CFEuy$E=}yqap8o&IowZpRbH#*I+q;Ph;7!lNYx&mZgYteo{%Pw~*p^Sx2> zadx^yCuNDIBw>Xu<@p5xPgV;Qc+aOpn};p36$b%5-(fAKiEU_O$~|v~oi?81Be<@% z{CjT)U1DS7cDO#AWND7I+VT}YdkjEM1Rp1KpLv<)m?bn|Rl834{%1}Kxjdk`c`6cv zRWahMs|E`NDek>J&FUd=tV-Qg>x*0dCvZQ{|!3s^h;Xp`T}`qScvaP zrxe#XkzSq0FM}zhKK-uil!Xy3Ru>AGS>c0Z^fJh;!9I^yFwfcs%zdc-G&)U78@v5& zp1fPPe+Y7=bESr=qTgo;mx4~cV#}KUiiwh&pdiTqsicyc{6<1i{r|ZDH-lMoQkm6y z{-q*(xMZg36&kVeao0lyADI>To=A`9D?^OFI~LC`9=%~^I+iLWy}kLfA48i(m7VFX zn`2EY^7?0&JJT~RXEvJ?yQ`1$+-sBLb+TZ#KOOeT9t9-C^ z_-k{PHXBp0h@L2c0fI?qcs#=uk_8kS_-4fX5^m%YqUwm@t-k~h(@kzuZb!Y0NB#5H z+!8PIeAB8S*V`w^%)_7Wx&)&sTX0aQB7NfR^}loK`ICPtT*VZ; zX@BFpBChZLz)d&1e)#8t&+n5wz1o^?XW{3=d%C)Me0)lla<3X`ZEd}@G&gXxgbl3h zIpe!mgn)p!u#t1ZE`Ww79u(5gfy#0FU1*Rt83FI{(QCddMpT9d-0FFCT0~W$%=LL)Ah50K95fv zl3+vJ`Lvs_?dP`<%0FB}GMQY)w8=mLqPfvePgx}tp^v};6ctHed>$|A55MdWw$k(71XnJdr1eN8V$aX^ zGhO2A-|k-d8XrjrfApnTAoWJ{Zu?7QAY&xAeAgH7h_!g=O@ZcVy(S8{ZpQC&kB_p= z{w{xRY8P{v|3uSwH)AoefG4kbl~FIC_!r?;XwxVh%NcdwFF1YdDSpBec^DaS3v7j(d)f zVzT^Z9}jLsq0dGU~&MyaM`D)`8JY|QTf9^OGK#$)p%BjT09wS}&00RC(~2Kbvd*2m^K8@^xyHkK(yaW< zNEq{IDtJFb@xeaI->cvB4#Jx49S{;IE8;;f>!?d|J6*x)+=>a?{`*v;$Ihpi)aZ;* zF_JY_9+RMGI{$W|`59{9zsQQe(wbm5eToAJ_+_8f_qgS7xyv4220$kzzp_S;>n7hO z`(9BM?L7k}+s;e)mqU@6xR@u9W_!jTXS-*@HfAVdaO)|8<~3v~jhMLjhM$H#wKqEG;{dD@7FSe6sweW#dw+dIOBe+<*`>75CVasB_i2Bh;^5LB2X8j-U~6lA_FyrR zP)Uiw6{|;&A&6yc?=fs3Y>+{TdMPioxx%&Z)3M1a4Q$C#apYvyQz-porI07!1D$a6 zux0CmZGqy|`JGdtp~wD2mOEz>lZ*z8QY8gJk={>Y$gAB<-CtVK_h&>7Qm;z)ru!L6 zRo^lMOs2p_Le|etYE#=`Av1AGSrifCFfkZMU5}Al!N=dKZwo&8`?injA6u&dGjZF= z3tkjq%nt0b#}CRh(C+8otCf`to2w`5l~DjMqvLt=yF~4<%hUJ#`Eq@`MEiA$J+TkZ zqH*(MY7@Q7^XzS1v3AMbra4*6jh$I;Cf==xw5={gQ>cG^xMGkuy6tl);AI|T)gD>c z2?<$DrAFXFog2K+fD1vXvGhp04M~PvoD1Fj@SxW9-jy{;0fX0%UR~uV!sp7J(rHyg zQ4`w6!@4~8Nkd;@sytN{lhmvT*ZAi>d*saWJgK=ToG?qip~tC&tNh`9TSB^<&RnUf z#pzd(@bS290p}Su9H*Q;DEj*E$0Gk(;t~tR8Dxyp)e3v)Vp1R;WM|f6kjsE;jtcol zy{F0gV}U|hCjvQGpBFUZ$)BgmyWH-EHl!a<;&Yt>0q!BVoy@ieq3n0!F=<-m*^!bk zj4p$`fMEQ*Vru_!9ecQS(44NSkq*nLsjCT}qt*QPnpU^Ws)(0va-@g;pYwi66ojx- z0aX;h2vuHz=1zHfa<|e=+`)^LxZ9% z;OWkyjkW%dRoqV@PuhTPipyqLm6TXB)mSa7)I;U6<6(Tn z@1}`)av^2Nb>VFH#-Y_y4k9PG_A7!^3NsA7xUA@dZhE?-X8pgEen?kvez|XHiLLyX z*NY1i?Gq`avgQTB%?!#*M`wIHZfC_bf=2u-tyDl=T<+Ns>hF5B^}vx1hpQ z)WvZm$}s9n{PeyN>Tew2tF6Ltq16op5#UYKG(YD=K;X3+ER{Rn3`S)|r~5-(dJ1?8 z`(Fa=#v)|#Mac(kNnz;ECgH$q;9IxLO*w;4;kYS)i0*j8R zzsPt|mpSTUjk+sQf40zur8GNT{}!c$EdjPBWoF(bEP_CjG_K^?MY|X`zIwm;5a-$E zM4UqFFlI~6x%S425@OM0G?WvWmu=H8wiP(+mICc$nkFdES6upNJR*gZ)=Z$1cV@1E@`eqq@&;B!fDL9$b&g{9b@9`6OapD4R{Ux@xmir&~t5Q1J3Ty3S zoSSdVj0LQvh@OeKi%*h%=u%F*G_&V09y`0FAooe0)QIu&$vD-;a($; zMRcJtTFevHi^m_fd!Bz~mPNISQbmhFbz-~A6=g#erIj90FO?W!E)AbDtE`fK+SIA* zpQI6Kgh@9mIwlElHQ@27qfztM@LO|hVEvG5tFy99;UH8}caGcX&}T0G-DhXgL0GO$ z3L9G3=}n8OHd}!@j1a(UoDQ3*%MnvS@8gp{UV1mSqH6V3g-+4pcPSJe!mLnq zvZWfi$jn-V<0PY@a~-=$&NJfE(9!WCuSnrBkAz!lrzgzxeWVmx*q{bsx}z}ks#}q1 zv;W^}BBMe+Bt>ciLh67|&`*W5z6HmDf8|gk4Jm^z6?Fyl4pmG()|RP>_J+8W=G38i z6UeaQKoKu9JSY`aei1CFOqXwV$O(ASBstT}90D?2%3&!^K;n1rkJVlKr-0S7i-|?W zMhGb!g1o5AaSTS5ph0{DGDO+U&bagMQgYi+WSPQa+;DqjW>Gc{4i*l!!5Mj-<2-y4 zd17h^4e&h9t|&3mP!Uyw{GihI7AR+9drUf-8okS%;bqO`MX9V(Y(j!E2g^cZ>1zvv zml&@Sif)1y&)R(&q6hjf@T1-OK?t>BX5Cq&$*zGS5mAmlxN0yMp^+su8!W z>>p}Tr(R2SA-f%uG7jAH9(gg08@e|y@J?M~pt~3Jpr0@>TC3>fV#LG?Tx3?Zs|Stu zT}~?88$5oPHnvb?m?q@x0Ou~VJnB0}io&?pVkQW1lquyddtRtU@In1b2!>!&SAYD}kmHFuEn71q%39CIaso1N(o0&@V z!ITunE7wwf(s4~OApkg&iHrr`MG7&WF@PcU6x@ZCY3+IG}JVvG^JRPF@RJDV^C;&TNF*)cs}#RX2Tce{Qcpu zc?5WPk*|N)62k{f8A8$tsnB7`!bG-{r+;LUpowaFa^q#m1KS1YM@h{r=88$~JfS9A znWm`YZyduQ^lrZdR+d=d+S7(;v#R@)F>wJ!dwJy-L_KdrL835@?XcD0%2X7;R;h69 zg-4{aH$%8%Di?YEpI=VgF~07B0%QrXp4E^@4KB69k#r)V+mVg$ zi_sz(YK)0k`NxMC52k88SwQ|jwOV)*D0c-ExZ|bPxWf(*F(E5@ae!^E1_mOOc>hVU ziZn{XXbAW{D(s%v{u-=wBl69;QJ@Yjjkyig4@xSHLVFG7eG^zcfeQ_|FgAFo|G_L^ zNtsk6STiRmBo5Ci`k%|g+Nvo6jCi%9$?9_|WM4x`oefCIKa+OwJG?UV-sqySyK*Bj1;9chPgVK( z)(U?kv=7~M%k0LtKPf+ZK%ItC#$v*dRCM5}yLfL5CncB7R#7@5&gn3fH^>!?ybMruMdMxhYxhWKf zM`8p9-Ti;L*(%%+nD_ZqDzEhSH#Ozwox-l*2YmFI9kt+u<>iB!j0{c1XJ&(5AD!=> zCUjq+f_DfjP^D2~Bsv^s>kJKhq#(E(JptpBd*8+7cGqRQ*3kRp)q{~N5^L)8z{cQ( z=fZ5kJBN{qRz_boDT&k8Sau|X5*ZyB=#wBMwwCiZy9?XMX;E8!u#kdqyEl&axN{Cv z$S=)M!^ECv$)}*s7CzCr^z0fVLLO{?lo@`Ev=L@t@B9$t-`hkk)H?(T@_7cgq-Rk# z5TW^HwTkkT@#R(@O%87_<6HTmm|FS?6M;>y)Fk%-(#axAT3sliHI6Ji`8 zSpVh_As1WUevm%>8A}UPDotbEea}=TGfubNRgw-;Q?;f>*PezfE3#^$k1kJzT{q#T zpqA)%{cX;+wZN27ij7x5{jC8~y3rH3I5r>{>h?rj2tsncKk}Fqs2|V9Ely(6?6R+k zEJg0Iirui`LTaly62G`AS&VL5jVJiwtULuG{;CrBD{e8JdZQ1EIx<>Exq|e6FFssI z42m9Wn>L#iHvH??da zfoq*lP$chlSRYVvf{6;&%(^lqEH|HY+~&|>ahh}Ns-VLPh}bIZl#<KGF#V4DD9+GDvefNk(Ml)E%#LMYm=IKhCXT+ThAtbmK(#G0B zN<#!-Vb)p`Nt=(XGAvL{W@=bB6I0p^b80>>k1>uLl?Gi~RiQaCEd)fmq@<0`^}~_Y z^X6%A?A5}nvU5-*j27%#5Uhgx;}%WAK$LQB12H*8OG^tIMKZR?C@Q854E{bzsw8cS z#Jn3@<#P*csE|}51*GTVJ-lpJUCbek?&9@o+zD>$og<>%#=y3%=)#}71T$q?ii6mf zOq+jc1^g(^4~u2p%NFml*H;s(?F8+m$~Ij1k+KAtbD*F=E)WpS;x@5*7lwfDoB0wnXdjM|P0?)TfM&l?_{61odBx~jkms!N4$4Kug0Oyy7H5^b^1318`1 zD%$AD|7@h8zFJz4b?kO+J*=r%|M#MafBnuVjmZ2dqFhdh{HB-%NF^!m@0UWX+F?{s z@#Q4!aeu6#nn^3{pCFA07Mh;M0Ler~p*AK?{XmGA_QK5n)H>Jz?Jyde zPr!-`C&nJA9LXe3o6X%4e0SB67q8i>@GQ-pDt?6bk5M0D`W+{p8}nxK%MMRxKFJG( zq%`~nT_hXygP_$6tE=!QDz{M4N5r8d5H#`Qj|!){?q|x14DYCZQK$RVeQFwItI)TZ zicD$()|DGpp{$(8Ww|IZ-}JJqY2?V1Mp}y$Y~5|cXs|B53!!8 zpsNUM&B*+RtT_GlA)k9U+sZG7MbP0b>*|HshcB{H6I8m>p?;AgpE^fIokfeQPf^m! zP<;9C?g|5~V~ZB#^*qs79X;6BJ0Rh-ZjZQ;ilE}J98;lT?i?dc?Y_ss_I)`j<)t`I zQvvP7#S|$asLub|sp;8O!~DT`%g&HKOg~7R)v~nkPu9TiyQVBpL=6-?VtNI9YzHY7 zoT-y=APQ`f`iEC_%m|ZAv>1;km$lOz)R(HNbb&c?77k^8fHW0)i-I0rN5-BNARnys zlPzt8F}@0phE}8y-7@~X!mpjdn_h!*Od~z3AZ*pQqk|ek7=YU3y!6(W&E>ek$q4sq*$DS_2iiL)OT&=GM7tGZM&E-Hn%{yk*+w2RYNp395}?&qP;39b z=%Nf?>JUgIYgAoUVLTPF9efZ(H=y6`k$s}Z@@}Wn%$IJUl={F)Qz_b*e9ue^8aFk9 zt$%e#hKUZ;&XQLNET{t#A6Zb&I}1%((#qL4%%3o{d!kz;>tqrJ%v7TnsVdLr zz0WzCaklpx{?$uGr%0M(LXR&}_Px}KRL?-^uc=FHc!s0I0Xk~)cdZ$<(}h(=YB0XT zg|UMD;;@qI0RIXkQbRWuHa-#g;?7J#^}@b@z?Bu;DPMavJr-%66q1zjji{mSUEs72 zg>DAJ)dmSHbPg7K>J;Pc$pdYhgG{bF%%7yd;wUs&@hiTJaXIhhQOd8Zk%?mJv+p4H z>$YC??)3+AeT65R&6ncL7@<--u?29^kQeO1>wf(_1H(2*^?eWMD~`V+Ql#PO>8C#m zeF_sUf&`4WVWLiGD${<}nIERt4iBPqzP_gWECF~H{U5eyi{`GK+>V`%5c{w)q7#$b zr^PqxFzK9wPyJXg9DDD_I&wrUz7(YUlsF`?-&Y=8hkC6%=p-B$OzG0hY~10<{uyB} zt>!!1)a8G%JzUIA0mfe5bkQ-7`PeWMqV1%yr6mjvd8=8*{uAR@8j9@lqEnvi^63|{ zvfSGWr3&M^0tk~Na<5oPfc=c@Y|hO8YD0A{-Z6OSD} zb98iLQF=)U!R_RuT~&H@vdHT6aD*T|r@I+>$`z{+&)AR_mZhk2=YN2({6xIvarX1| z&%sS6S~cRTc&Qx|yP64x)b?iIC`}}sI#C#{i*{2nAd9woT?8@l{%j%kkt=tO;vdx& zp$AOH5G3%ARQ&x98J$l7S2~)-QvprIBK!;>tj7?#f31_w(M^XLKM&1u~BEPlCoZ*SNCZ3??9$=$IMg5^FnGG;3Loo1BDz)X)8pzR*gXZvW@0 zJb_a6q3{>;kAaketpM+rLr1*~&iVp_n^xNR!m*`c_7tga5-cgDO*pQ4WOHjmKma6^ zsOoQl7{o|~VA89RUR<*sZk4U3u0E%wBT1?+&xV=v0xKDbO`?+OagnJ{SFD1IDlOo2 zL?iHi*9;`mcQrHoKiRCBEo>Z`GVOh+Me zS6=C{W{I}ZH1$nx%jLn;G}RkFd;QqRPt!5vlU_~J@h%@erQi$QFt9+n^ulc7W>c8j zBofV$9}_c+x+oa`)YXBXd{M>#mo5LTTmr-~!kTe`J~5W$u@^zk>rK*}Mbe~y`e`ch zl&JGNm{gO{!KlN^himk>&24fze*EFx_}n5PTz@A9v*2NLDr8^l6gK8Joj@q&4;*gO=S?XIV$O;5S`?@%#)E}fnM>j@mH?-8gToYigA2c#&F zG{gU|%;7lOMy?kbTvJE^&a16<`bR|>d@B26F0tk|192twYbtVNWMJTOl;v0V5p$N5 z&kYqgBZcXS)rs%bt3Rcs%|7}K#%|vjy+tj>jg)DLYm8&2|9J@i)>xDpV|re(2^e)5 z^`DTEM!6ozCXcf81wFK&)^8xURWuy^FkMz=YD)ybD}9uYyvqNg@gKyAXw@k1gGPIn zL<@Bu(_L$E!>vuPz|po31!mj&_*7N?s!@4fUnyd`;SUkvQE%u!mQ0fiXu_Ayz1HpY zmLOv2m_deSa$B57g&{-Ih^i9AqDKm@3JhF`ZW$l`?9lxh&LnPjPz9guqA*+(14S{H5}l&nv>rAdG_Wo78;CS*{VA`x#**@?Y- zi660j-}zn7a7I1osPWrUo3I@U&As~EZPKOor~-H1cBQ|2Uu5Ed^AL4 za~j@pN3o;Lt4PW3ZywJhF#+R}^|~~&&reUPM1{BJn&NZlCZEosMQ;9fft`5rK(Q?B zVMM;$&J6^9Qe_zBTP1{$8ByTi4-dHoslY^VrAe z(!Wj=(ZvqtzoUx@?~#`UJX8I{mQMU6P~%$cmmAl_f-avVtsM1arkSy&lw4lBq?^1S zw1ORu_@jFM0)5EA-{nuAmV!pTOjq@@QQZIoyt=;lw1UTYI{`|GwV3Fmf(u!jjyw0g z+4AwS9epR?g&mov`DP#h%Fy=%TSYT$$gXXk7JS6fbTK%!0no%>D#DUe`KY7VF z%NhS38D-nqe(qu4kuWQ88xyM-e~T6HYG!@1aGOBn6HJiPiV7QnlZ(9{#|mig-f5{s z`N^B5N>gQJ-s7d<@W*slq+~Hde1h}So3y@wS7_cj-t+WhK(a~3%vF8w%@;7aN|G`| zJrnp#-Yb~ZMTb%z%uy#j`)`l8C#$2+U1$+F`av9rEg`39Xm>IHg*u~?*Xv_i^XV^{;=JxD zl8_)^kKab-i4MzBB%gMWdYN~7y6tM>YcjjAzJ&jkiu|2?s-$~Q=`{*Rgb5|i0+~Mk zgE5yoC%0Wke6lAL|0H`Z+Le4|qReua&nBqFiU^C6LbC74VY$(dZo5GcSxQaw^_=j~ zN}T6`Q8L<%3XJ1(YDPN)O%w-ae23Vi78!j`7e`IKUCVNQRp~T9xJ_t%Iw6_2CfTSTOxS!^0diSSv!C|;t?{|Ld!^^>4eS%i>4^|ZXFd{Y2 zZ04-Laeq{IrCIKCqDrt|l_dQEN}{t!=db=;dVqeiAbNEpT=f?;$&zMx*ywlCYvrup zjar9x)Xj+T;~ZPYY-yw=Tx$qf$o?9N%-3rp2vk0u8y~+8RXSy(Nk7!CPSmx=b-N#< zqb;+684c}~APJ20JwI<6nTXOYe(myF=b9=6+WHy`JRCL@W#tJR^!k8$GQ@8c)!Cw2 zA7Ppmylk(XBGJt7@nt%!2L24U>Dsg9Uj*_gxqV)7x#s~N4|Z!a6$Sq39=7Z9BNI;L zx2P#uY)JMSU4CQwDhc%8n zt(@d|jxO+@>9$3|bJjEGOEW&}jt(ii|8giTX-uQ*(F2iYH9Cequ74_gj7$1wwVIOU zLH6W!`X@!nMc396@cnuhXl-$Ky!(SgKRWW;_3NmlrPN=DSn@K{^CsDmfWEk544Yk*t1&jk08=4ktcQPKi2o{q0Dyva-W*z<@~)`D$b$)$*w!peBW8XI^2jQ!p44(9 zFkvV$u*8Bi2h06=Mc>q-apsTvw$EUqd>^zj^z76#oxZfs8=FsFqV-Sv-j@;C?sY#z z&H_U4hAzAR$Ww0voPA?Di;RX{-^%T;bQA?9B?*0F-|^h9M$($Q-QFS8x2cIbKT+~~ zFG=*fT(brJj%{*#yf6Y2?Hw&w1wO`K1M(lwc=}fXbzB=?1XliJSEam->=K##>7fPO zh16e7a|TRFSwqOnay9F}#-0+FO;8xi@pRx7@p7XqYaDLFu7VyczMdFQ`d3j(a` zh>A;}%uD=$utmn#5JyHq>W!r}1$nL+gZJ}*Lug6;qUOFF%i`#OJG#DcfbVpClK>Ac|i%Y(b^{xLMt_5I>U{6JJ%PX9c6Ty5>?bJ?iim?`Bn zk>DdIevfClRzowTKIl;3-s-{Cb~^-`a5tyEZwe1<*759*c5ADVyKvT}+GL`TkU zg*h1;0@3?R03=^%)A?=oOkB)^y6+I*JyuyaSz1fqdYU+4#^rvG zzfKmyra@I1r4A^$AKIgb?e4)C7-KHa6u>9@Ux85WfaO1?p+omG8DQ)-x_rFAR~64z z6m8@o9rU~U6&Z644UK<2W%mZWz>L=Ali6mnsZ+rotJd<$uWuPUP#Flmh)VoH1G#mE zzj8Z2BNz>tiuzUe)s#1PG{#-qX5$U{@pvQcgePX&w`vQK3{*;yms<$~Fbn+7SRg`f3C;?}~W8y*I0O zD8y*sa}L5e?Emdbxb73^NIi__P_Q?)N;UoiGyZg^onZ*g#P>dph>4GTq|1Fxv8l>j z`_Pw%y^;3Yxi47Q4wc2`P8@tiqaO6AOQT-IK%?@<&Hm+{VIF zq5Qu}>c2JAFqtCfu!>$kDKwH`_6GATXp$J)Vu0Au5R}Q7Y;5ZrY^U><4faL4@dw#| zF=Q(cPEy?MZ$=cnb`udOlPEN0jZ+0=)#nQi7HRg*B`h`mK3SeC>LshG)*&g>!ViTsTYGq;uz~4D)_bzom8X zue34><%r5>2t&Q5s0UNBjF(OT3A#uyPbK|@I`pn9k&bI!`C3KRNU?~q1hBrV97A3B z7qJ!MGNv0UYUw{OoLVPWUfLt9R=FU7K!nzwQ*_8~09LagKh4U1v-9i$wvpnQacbMv9~9JG$==z`J9U}VK1-={7S3r|Eq%#x6wb}Cs_Kmdobp=yIZu23=qunCpgGS9`Im*- z!P#hj&snW4iVQPZL=psE-;r~#lBSGrEveoJExM&1lE}{JEg_)5i?@cp1%Xm{Pc53tEPC=Cx&rpU7j1_L~>kWw^dyx(9 zV~fKL_p9nxy3W*`|7{$t#8tP=Dlls1$tlsQUo=G2QF)QP1cB<=N_S@%#_pboJ zb>zzcA|URZuKrAc$dIAeaKXXykyh=t!*+&v6O(KbQx1?C-rwbwOl#~;ecMx>Ri}z3 z))?LJX=EAUMvB2;acKGCJTG?T2hk4tpGLgD1^nF!vdz2Y+EzGVsK3wZ^^Hoyu3`8H!g^8hr?BG z9#VVwXSs3Z=;cN`Q%!Wt`bHUXXJ=nTLG%TTNp8Zd$og>G47;p}pH<(*aO$A|5w=sP z(b9mm+AaHzQiu~%EfCJ{i_tU!!g7|Cdd7YQLf?~Tva6r~nK~=l^7F>eH|)GFS{w0B zQb*m&-Hs7$Z0%vVcx|>#M{n!K@&gbjw?`dW~LAFFXUUd4p=eK{vUC01ySqVd7%4?t893^Arboanu;i;s$>$w zma985t7XV?70quk0G-}PUR!x5+cwHhkv3JCC7q=-6^DcxBI71U(SsE@ra1orG3{^+cU7jibG?*8q4$% zI5iPw`%abHQ820fY@^SPoXgAi-WKIE6%czh_alhOa~2JGFnsD2nbmk$o~JCK3eYh$ zU{R4QA;-MVqc%aX_Cein{~_K&+NmDSZ0Ma(b5CR6Z7Om>fcv~&wA7q$s8!1qzN8nE zgu1~=tyCDzMp?oa`Hs^`k3_Nm)WoAq4G8fDo9`dntQ_2*FJ%~q zzc_Q>|0Y_-fLec_iBtbdP|lx2HDt*oJHrw-SN5LMWV?Z#^Ogx0q$40^e2|(6L&4f} z5Y~^I{Cp7AmuuH~i^C@SnN{X1Aweyx2p z{Jf*=J3U1L`VGE*{I4#^%gaNF(U>EA54cSqg)d#q$h=Fcf5y0xeG`27-NE?g-z6FA zmx6Ea9@{5?Z17=+0~zX2^XHGMWp_Vg1ilq%3AP?z<4eLTQPJ~Vnw_m5j2{BoVh|`H zPo`sU3plQk_WtR!vsnBOAgy&l3zlWUNxek8q#!Y&5=>F{RDEB|%~4}DO|>SsereHl z@tq?OID>OB6YSHv;*pxQ!cd7$g%=m%D>OR-oLn96znYOSxs+GXpMFbmyV!QJ1C8?X z0Mf(lzL%fh5DxPG0n(phCI z^^Q(H`wd84&&-`|Z8;>`cCP!f;cX?Y-_cmKwA`KrUHr8rV&)IFAc0YjVV@MY-xF9& zCwrSTqQ13V4;!TwziJlzN%;M2 zc$aGpgM6DSH}gfCzmJC64d&mkXV`)cXXK~*^54>Y?G|*r1y2t&YP3J8QJOAjkWdKOYhARB$p`ejLgh zX7?Y%7dCspp(RVe4h^3br+6}jzH-RO=YpQ^n(T?D>^!_uGblCXO@Y(;zOpv*pXwXF zoGza{Q2Lnme3{|Kt_**_iJ)~C{*d}cA1HJx84GWUYzGBe7l{&LaeONQ=lsiUwL^8T zuZ%}O@}!QjTN-KlMwH&{eHMUP^>MsWaU<6i*$ui$6G!6{5K^@A1<7usFTY zm2+Q?VsK*2vpr!Tya3I(saPNJVNCP5=q4;XL)qiv$z&#Hz*m{x91B8q70OyaBmcZ% z&3g}|XNrq0+@AQ>`1}eRZ_(-kCnEf$`iD2&na-3b4b5taS6Qm`sSQ!4$?_L#aEgfu zhzeb@LlC)+j81~>(i=T9!{orAnR)K>zt>N_=YgNLd5YBD=^~+J@ejREbFHdtPYH}F zCl%HGmcc})p>{2 zK(YDb7b)4#25V9?-oPCq5E*fG{+(sO3tMBZ0wEw&FW_Ip>gW>Lnq%{0TV%))(YZ0lq6*=RS%%eIAX z<;NdqZ#wRZ4Y#l((4B9dQCly+h8HwZej^K3ZcpnQsodP|{#NKw8hWq;m5*rLH*Vaw z%FSU+7l4 zfNMIsL%mR1cWYy0-0+5AwTtjkm6Fn=p_)2HTh-2qpYKq%)^$y*=eGWH-+2|6?{IlcnLDHrtf9daM=zIv_yi& zrS!Y^2Cp89Jj!o;RiNCxy@iI{x=lRuoshOj@U?Vx4QXczIHl&*AbM;~ z@%p-NKP9$Tj<`9T9+7nncX%F;2)wu${(+jJJG*=hGh^ub7@fY^6=d4_bz4BV)tPi+ zeI1rtbt(6%}eR@`u zW?ZGB;p)&8^R{k1zG^c0mgVc7(&4d->U&mfapxd>L+^e0t!BlbO_440&&GRTh;J{X zK_k(9tGfkfr7Z-*cBi`RGxwP{P;+>8LQ|MH>uO7DJ*#oMY1@*eN9hhvhjC5ufwsu* zXIMZZVVA2NN1r2M?=Q;CXs%?Xa~w^0^c%l4ZJSCkk`Z;>R+e;}CcL;DILq@W?-%@q zFpKc!`(LZ865Mb>PxJ}z6Jw;?vLVd|&5G){5c#6yMGQ)kfF9L1@n??X-QHL)hoTx_ zQorYo7+~t)pLlAa?#hfi-l;`-4K|xrr!&Fl&5+7JcS2dI9u?djy0;Is%rl?)J+5Y5Ajb&x3@Bu5BxSlM`oqj$XstO0KT+uLWj@|75<6d`VC%Oidb}q z`!3>Wl;YWbjpCVN)-#IDqWp2c{i)6=-HYa_eDve3OS+(QcuWRgPo>|ZORMK`i28t| zTpIZ)l#vL@mEr3I-udGx*#xEwvCz}tfcxf5Pdcw>_{`2b&6BmibvJ(9XLsU`t~Qod zz{SbP@a-@0+%k4$7iTpwPS?Ev&CfY9PvURFAO8+Nv_3!cr$3xx1^Il(Zh0HvpK!&o z?t5_3m}IbljV{u{8@E=_X5mc}up^R%d53?+N^C4Ee;_(K<0CCezH^ z`$yx}>6UCcyiWPQ-^3dGtfu#!InQNBu{m|B(x41cpMkqJm+txeF8bFSwpXM+!eb$UxoT@D4if z-^=lf^0fX)KMHu!l)WVPO=m}gZR7H7PCHkO(d5USF0SpK&+Hr9Oh;XL_+0!=YY=66 zHvvlOaP>qbw5;gr_Hm$)3j3zs4Os<{|2bKEVMU~}aKGGxNKS0G9V9IbT9hi-@$q)` zgeb7!MYx=ehpfnJqFmOHpvft?nC-yChf$ha@&B$nq-s#P(O#22;pZsgOp$i}at(t> zWiH*jdD}kW$<$LmgC%QIe4d!Gb;gQ^PHOCHl8T;m;{3I^8H>%FpEyf!5Dqb>x;AqY z*weoXcV}-Dq%cYbA(REUQnUS%OIYv}fxBtw{mX@e^YtJtntVt{)>`YAXsA{IJ7SE} z7w_mB-$%5?0(Fg=v=w>gElO;GJ7~;#?@$O7i?xDjb@Teu!aoyjyy>lY;tc*lHD}^! zmLc5p6+_uL#=m#eS+@)?f3dT+5?mZE$euTK--vdWu?L%KMfPD6rwVqOIj1MvZ6Si( z*l3R{3$#8}Dmg|J&_zF$*J3L~=3O8YC#P=MTL;}Mwpsx8=tBiAAr z5N2g}=Knxbw5NDgLI)`+iIuvN7g1IPK}}(l?=8(fWpOKwk!QH=|ARe; z@$9#5bx*+j0iT~sWEwcR^3}oRZwW1(u5iGj+3eL6|JZ0r(p0bp-a5zY`1#zAIy{AfEK>jpnwakK?5u!Aj$5qi_1V@+!(b`R|5b1-8j0T@mJIG z%Q^y!=#0(x1NZ&Tl1%TqXxWFdaj!A+g4G&@o2 z(+LF(e~Nt&&MVlZ;;e3h*W5LKeT{8OTsDOjv0hG|$JY3LW+tORsVt8z-ZLdAbTFth zhuElNB}UPT*~8%dYN>!wIaa;K;SC}yDu52(Miqec)Jj9fY~lg$kQ$YzWpjwHYJp@;^hjJCf$ig5=9$hc93B|~ z6aHgBA#-OE8$H0-D20k>5ykKBdi`R!sbT1EgKHM;EvZcDv+2Coi=Vx7`1=~fw0lx6 zF2n|`F%J1wQhQapoa8N-a&@II0RRP>6#hd2O}d1C3s7!fztWCcw)CRf_3TZ+xKiRb zsH?gwddG2}Fk(ME&+GEtD3=$)7}fYgwTrA@Le13ySt(yC3DQUH)PF34&c1WSYEvKqn4|h`jLb zv9UUH2l3?PJNn7`#^9kS6_#mop-j8hpJ$zL^yAgP&r8RZvaU8;NCEz2tuJUN`VPlY zNp&DJ8l7CUn0i(@mlL8Zf8c$PkN!)UXtX|Wn*;dZC*xLo9_8YM?A+>96Q^x~2rj)R z{El^JCD!3toH&wYVYVo{A?gh5Al#}4Ch|HLdJ*G38tp5$WSS0f@*I}jHfQ^|hRSQ# zhe3tm?Q^;QAHW>R?LMOJ_6FT9mNgg*Y zd=dzo>g-%R#M(ksIE%@8rt6{7e7p~a|g=XBcwgfv?x*yZXhsGAvopTzxWfnL;`;Uhj0SsWJa*@1PH|<5tGJj zHoZLN@}Su3nw3lL9ubH+CUFWSkHFh#co{@fUTg&HhI!U0UK-C0GD0gNVYiqSiQDGW zKYqTp1IxU@LE5KbyKs@o^45Y;Ctj51-K%^oDCfB145&RcN43zJVHU_z38(pzRxsgO zN3M4_n;cgg?1l>eqbb4U_9W(vtuAk=A_uP+v9?A&H>)eUC2U1vj zxG#lTeKU03bkLV@l%x%#R33ZrgLh%WjyxLArabymg=BB0X<>7QZ&j>#@}Jz zF3RMAB)b^d__>DCF{yPKsxlXQQ3bHDWp;j9Kv5&gI&e)MeEqGCS(I|6Fy0hYQRvAH zFtpeo{<#+-O+fyV=iM=h@#n#JIxg~aGNlbHILUv9n<2qW;9DAVEwNHB%Wy|agne9u zT{7k`f3f>2_%^ey$7tWei`+o2Hc5Foy=`gQb9nu#TthZJZ#-J0$|&&a!w)=zjc?o&|eSAF6=&fSI*xaHCZ` zYW=hDsW;hl?KKKUKx!sh4+}v}dUM0roxQqjUg4qh`0wbCHY7$HF=w$w5}R@NesN_aQMp?rHRhyNz}Pw`sfr^Y3{R%$%%(uHrvR ze@Jx?9KK>j`E(>K<=*6cYCX1Yu{{w=c3V)NUG;+!38tk5jvm=(F zztw|r;>P5pHhMAk|E|2f*)MmKULsLYv*s#V;1Y4!7SP-!wbNAsy>Ff#P_TA|0pVy| zLWlK5@y6cbMVhT>ECMk88O!BssHk#%vbFZ$V)bQ6x_E#3P` z_!kU;?O!&^0arB0zc9Q^V-~1XMeV93B(pO@J2^VgI8EovtTK|ok3v=J;- zOzqDSdu!gejb_79XUJ)qqUzB zN}ZgV+8xG;-~6>Sd~@dCyVA}jTR%01&z~-Yx~;>jj`CC~`mUyKY-9R5;d|a%L_8iY zz07`9w!Y3Y`u9`SJ54P{B z0xB%h7SvB1N?Tc>&R+>zA8cby9s8WWh^vorRHmFtf=Qf7nf&QH9Ak}SWZh#sf=*_g z`LMY1NDFXfq1@PbY%MXkJ%Y$~ER1FB->N_W zxe&f&$`1H3=H^O2$wt2CqS{~h$!|OfqMtJ*eg=+C77`xM0r3ifam&Cp zUQGCiFGf8&{PzT$OvN0nPQsJNw9lB!EHXS!_Pe?^IddprLTxW~mDaPlWpx*tae*(X z5lKun)zwQ!stH_8P8a5tiaA^Fii?Wu?qJ-n=MISJ>bym4W^wx4F5z+ zO6ZreIkJLOhP*z1mf+y;hOu<{+AAnra}y<@Q(N((T?1P_dZywNdlBBUrZ zzsh|i+j`{o)fNX+imC`gY;xYgiMs(MihQKRxqfOhgHK>xySxva?m4WE~`~vbInLOElhQ!gznI69O)u?@!$l^ z8W}`**dB7@C0oxv$1{z|9px5LOC0jD%5va*cuI2m%FWh%FjhjYb%+llZo*CRTl$J| zxw*C#`#S#AnYJi0|E9Jna%-O|R_Qmh$d>#pgS(|}8G|jn=U=-cLv?I9(kghmK z;Lw{ciONsHh|+!jV>D$*JMnJ@3f1)|2i}!e6rs=?A(hZu2O#YksDGF4(B{?$nt482 z>}VOFm2y3K$JsK;(zSHynfxH20xs*WJZOGEqjE+5@Xw03$p7f12vKx7AWTXuR4@i= zDh*;kb0T)}D#BQ0^ZYX3;N<$2=GtbSoIKO$y=o`Bk&6rV2nVZtX)SxC48Zhk@+i~Y z^$aXXx}qpGdiu)t$gGUE%Uy51iGQ&(4is8#HZS*tHd?XoESu>rOm3BQbW!W@Hu2#o z4R&fb`(LD74~W_N$uu$ zPhSvj4fwh-TS(f`Ivr9%o2m+?C-(-ayM4q^*Ssvq0bGLhe-qKc8e&i6uxhvzd8M%< ztX{X|ti)&*zna>b!gmqhNX8Ug(y4|y^_LUCbL+OpoOmP$hw0M%L?Ah4(&_ceY{8ZL zo`>j&h5Mp$!y`2!DruJVFMO4>BOX>5=KVqm9}VrT{i=WNNA?e;jd!rD(-8XsX*oF) zU9Mm&3>TBzijOOiu_GgdDW_nY&$K;l@!`UY6#^Yo@1 zs(kzl5Ab@ho?%)`>^}5lh@S_^n-ti6APOf5u*?e0J}SLb2*L0=%L{TT#sZO_G({3# z(Sc#i!Q!%Ul2D|$o}zg&y3jBA@EPSI9+7`W=nfJt_n7&7m&@vEVO`@)foRSO8zMOO@YNpa4Tp~btqdN~TGK$3f(EgDt?LArErAs637s&}X zSG&OUtdQfe9otY?FrhSWQaz1;_Zm}ROm;|hTaQ-fb4VSPh|8jC8*f2F#)Jf z{0fl7PBuG%jzKMm6a!ull!RfL+_1`&0kF>3c1=_iYY=5?`jvP!b4iDA=Yp=A0aLIEe|0gn*)aB z5z6pCo*q=FA<4$<=DZ8RL3WD^g(MY6-DvQU;eBm{Kk+6-{cSwmD?-TJabP0?95xrJ z&fI@^GvT)%w2y2qT|Jg?nzhY^oNpy+OdEgxxN8?faqW=~9K%5RBu*y}H*u5mXKt~c zy|vBm+W~$_#m!Suo%v1po9PwL3OZ)53SA*7LHiv4w4t8}W(Yjd;>LpFw$|?^I9OrU zS*lph&Y-4T6$hKm_Qe@J17GzcI|mr?WDV(mOgO+Bw;w3W&1V^Z=Hrxg=STU{I%WT1 zLxCFMPA}1R?E{jxNpv8u`G%KJ+5r(UaT??RpXPSM?ja0dL(8b|ILZV$vAM#u>6QkM z+xR(M*5Q2#7kcG{xr^4EK}$kQmCmt+Al+sD>b7B69G%OErA`wklSFv-vZXZ6{^a2~ zzZBfM5SVnGtiZ2YvW;a3+KuXm3K7y-DV*_M>(cpfZ1ocv1s~8DiA_eM&jwdmg;2N# z%Re_YJyRgZ*DM5sWI`IPLQcZd@PZwTnnCq;n75!{d?S9mM5`b>M1SMd4eMp}P81ez z7AIEJc$g{_?13sIFw+_I4XCSr5l<9m(z8}CL;33J-y*#7ov)g*GND@XL$WdS2{TO- zS7^q!U3?pGdp9o3vEuuifpi_58Pl6(S{z~)6%**Dt7n}Eu z1xK1~D#(#1UdHs{+s6E8O}5c`R3F#epp3|-8|0eRH$B#ETqiq|bbz;Tilc(U6@>jT zZ3*PH>|~ZItieFh%_#wnJMT1?tyU{NFaSRoFZ)lfuB&y6^!KF7zu|fmp2{t6p%8Q? zA_icDDb(lG+>FkGy^nIi&Ki@@DDT|olb_bWw$9Yn+LSt}7LS-f{NJ5&T<`&*9txX6 zKrz(GM2nzc4tC<=6f8-+-l;(8Xq!fU!gdsCdW!(hObjx90RuT@*yY}6-oF>rEHxWeIhf{wfMyk8rE*X&n_Et|v#mYo?$4o3d)HwHj4Zp%kTQV>-)w7PGGqs z4N^CWY+17W3bbl~m|?j;hFXjMZ|B!jy75VRyfcQt&Ksz0gjkNhv36toN2nHxA6^8g z{a_<4cFb(V?W5O`c`&+1ftw4sKd*Ez(%)?Q!L=Gjkskg~*h@l)%81f#`2! ze+YpR1;YIMID#HFQ-Z{>15d5OFgxBqh&*AGHSFv-E099Fn&V2$wA3!@>^-l)$Q~vN z0VbZ<%t(VNpkxFP3n9^a4P1i5y5Y6^=97mvLOh9mg=y3WxMx0fFV&l zTs}q*%2DN}_NE$!(Xhcrwg-CQivsngTX;kZZKw$LpqNXNXO{4|qd1Lh(aR(WA^55d+8sNV6;_+#*p4y*Xm$n4!aqrfC)6DndoW?7-Ft@{>c zqg6h2l0Fi=HuF)616=6pPKcn?xdwsl%GJ5j1xwSCHfEH@rx{&%B3#2X4y_L(AqMq) z-(>=nFT<7LP_wr&b9Jvn{a&Ke%OFCl5ywDAm*1x1H1;*`URaJUYGL?UlcgK@(Iup`qOz@;C57eNP*!r+wvCl`oN~!o?dd^uD zsASnlhqr^thNHH~B33NIFj`RQdF`33<(6_%hZZ%dK$b=?|Q4U1QJJJ&1 zcG;YrGeKrsI44xHd8DMzv>hFO%&56bZclD)NB3*UkLF_jiE#cxHxUy)!No(4h(Cny zm&h8t1=N)We*xq*DCv!&gbADnH`Vt7VjTlx5`}f4jnFAb*&UYE~+`C7o z>z^?E<8G3P$t-%<92FRff}~iHD+VUcWz7O0DH@2ViLP+_1?G5X z{G@r``g~R&IPWTiQC_;4#g+29gzxmbs|qLbe|c zXZD}Hd|K04kbMJj;g$pVqiq|)f|zob`- zMKOhXRl=zAmNA>J5he(~C!dR@2nE!<*0Y9?U|i&3>~Y}P)5#EtolMnm!W=hbzG(9T z3ttLp%Ok{LyX1(^6}CKdGkJcB>RKRS}hsFG4wn30I zrGpDz?GExqLT}!UF<;cuUL0P6&kR?bE-wuy7PEW0tJJd-~EKFrCD` zjGZOukiXG?r#pfsTkFE*QGFxOM|g+46rU&3dZCJpA07vWT~!qaS(2@ZShNyRFqFfp z(jU0FcV(QS(_q<83XbU^2-t-XOzZhRYr+P&LqbJ~0uoh%!jxSX9x<3o#?+bzljqzr zgM9o{vWzAxD}y646O0ZfSu$<#7t6=ZKtsxY5eqN?ko{hgLh@#{(W6EHUE*H0BM2uu zTg(jOE2Ps>3di*@zdAfG)62`dEzUo`{ywMrTofeXMw7i4EroY5wq)njVHoutHUS6Y z``q08O{=_h`Tf_Y(U~uIcP-xA;0A|vt3BwN@9t{zJbiX-+_bbbD>wH@N{B*|u%{Ro447U5VI`Lr^m}eD&Ubnc`Tprs!2|yvLmln42PysY{+DYh-t5~1zvp$} zCfy7zo{y>eA}1kutAQ56AkhM;XL*B`>9w4z34wb`>KGElKZuoW?WU){X^u82-v5eQ z71YqsXma0o=FKNir1IE2`-rQ;A-d7~C$!@ca@nOomM|JIvK>=WfRO4+g}?wlaOg%9WWK*pBnDfb%ujTUHt z7X*Z+1}HUV-i|P1{c2AAZ&|LigceV8yr$8)y(AR^BxuepGLN-5CAaYkvP-~m##nYy zI*WMcg>IFM1JNbi|5&-eFbuZ+*8=0CGe)S%*!yPcie?Rxp8Q{``96X~{Zs*x*>q6! z)ns`G|4+Uw;euEKOpTx^3@A#VqY5$>TEd-shp}^|cI(k67b?1}^fFPOVGv z?#f`}>3kdAVQt~Ysd=(K7ruIM9LUg1t@)a(z<_C8vvZPr^2jVyXU-=u$b<=CUk=0stIx_*-I1xL`ti|fF|B+xi^m6xVgP-{l0gz8}=vjMP7CB zlL#uB)`UXS`&#S4PS~dJ6@hEs#4jbx+|X0ld!wo@Zhx&k={wi}kTNlwuC4d-`JrE2 zd*1RJ)htA*CJ5D?P0S4{gyhV0&&OQf+Db?bOa_J|GnME3w>EZM|3v^E2l62*80Y4g zk(Hl6FE&?9C~J4PPW0e!g89O(K{1$?9EFZf9E=ngJ{${#^tnV7lD%5vbY&QXEEiHh zRS?BrF7`bx&aj~>IYpF`2*nf;m_~xHC@vOONm_a9F({%<2!206^wqXjiJ7qg#kmns z-%;H|nSOJDh*)YapeneRNR%uQf~2FQ0PbjYI~GVwk-NKirQ+GQ_zZ!%_Me{$Jbl1Z zpUcM!2Yt8wy7(U!qq8i^En8F`66li~rniTlAyc~jQlxaXZ@5p|%N*K>~rrr~7u zLmPChbUG1KfQKHpX6Y6YLPsOvIw|*|ZxfDs1Q(~rKqhWt7gs@A`_((F_mS{aSH=um z5(x-$3P|}*M=$XXLtT>KfHzW&C!#pvIx^7ZLa(L9t+XIC6om{Rt(PT7erR{7G7@d# z@ku*;dSoG>H^d~RLB>jFus{DpR%skHwP2jz581i(FRQ}rWWEAytEH+~`^fxtmZ71c zwSlnUI0Tyfg&&^^h9^R#%gsw@Ax}E;%CxE4#s+#CS`_bdR@E^f5XgV1PacGm%1;p$ z0qDK!|Mjtq4etQ_3Z0Cene9N>`}lzfgY1r75xe7ds~t?2%~uAat~qFQFhFi%{^=!A zLP9Db*eo02@_hI`ynR^Tm9YAAO=~x98XYc{ z8K=?N^i+L*5O)GSY-F$-&Iyrq{iEl zTi-1P$6XMg`w6M2BG`XTQzA5U@Ki@fdk5%2wd2nOaOFc#7rWUnFRz+3r&ZZDdTYb1 zIacVufl5awDJn_1MDb<@4-&OZ>#uZ64uSMYfPw~vqCQFIFLRpaB^ zgm5u2_b~yoGrpUP1sX-@(_^ET8H?O=zBF+ag-VD@ewH>~ZH@%ex6zp{+-e%y5&=Pu zd-gM=xu>}|*5ZgFHDnSJ5<1y{Orq+%rKO^xaz9zQTRon`#@9*jq@RlP6zu~j>2LSC z5{Of@FXdMlnV{hBSseZ_yp}7xwgeYOkqt@y+2vqt93g;tURz4yxE39xSu^F%d$(e) z)urS9Bg<^LfWwD0@d6TA%{HmD1`{0K;XJ5UZbDR;TVbU5I*ZD@Vbq0z6)us1*RkV3 zp$OVhkgn`A^kr>TVlEHOPh_c z?+a!XJMe0Qmk}Leo87wV^Bq6+{`SFj3~&DhCPFe-r0*IU-Z5p#>z6hQ z0fu_+CFDh9$TS(IZ5R66OZid<@CTbR*aMvvT9r|1YQE3gy85tBiJR%Rvg7zz|GF(XxBT$L^AmH5(T`G-;JqYBG{cK?u+K#r0 zXJzGxpw7#P-^K8HxwuLK8yZq3g=p^>@6Y#W#NsX7ArwDEp?V}S82X%o*MSz6u9 z0YqbD>fiu12nPl*nO`aMr3+M6w5KXa*jj-NFuV?y0q|bq3Ec!{XVjiQ!%^s7-ck@q zH9o+{;@L^Bd^||AI6*EC(6KG<|CA9R<)J7ruRqGgr;vO#!kle?;wSR}Pnm@#8?a^! zfL#riE~N*uc;HkK9D+Y7*>pI2xfG zCtX{=LI<{BfPEzpz5_s0%-TwC@Ni*oZHYX^iixvIzO%^kDj-&y0bEc~NjuKIv#W#U z9o5e3DlyR@Y1988Fw+$Q$CY0}T4IU1#5Fl3WpOLf@hXtT8!-DySFFvxfQTxj=ME~p z+9xOSmq)T#{)eISE1)HkqG=F0r8Irq_G!1}zfM5@02-8yYoe6>S4s4%n+TXJ)5^6T zoo3O)2g8%OhF39UQ&JP9m-m7Z4U_Rl-FL;#dS&6+?C>|^s;ma$=8T$tyD zMja7}Yb9;bxFIuX2g}BqQ0WfUh>$@fOMo&NDaN)8ljlOckSQ%CWrt+*&sxg7rLgr4 z{+9R{alcn)P^MK?VOHARG(kb3gD`-X#Rj>?Rv8^1{lkOiQd2`L!160rEMMLgnU1ap zj2-{IL;2a0qcqnwZA!WpIdn%ov=i|A{(~R_fWq(d7h}6wjO<_JqH>p~6onUENkexNOeKz>TFn_B37m&(1w` zfO~i(^S-6d-_jsR+UGwsi~(qfS*!V~@rT7(nGKrD02pO+k7V3ROMbV4$;3a~8z=AR3x`5Ug zvtFPlW|vuS<*FV`E8$sM5C3Mmn=FmS?+K26QVm(!PD^swUdR4$B?5S722fMpVX1V~sTkm4FWA1fnbYH6G4y#7pe8FuQ}19z!f4FRxP0IYz6 zEO9Ll?Dw){^PgRm0rLz$%p4CVIPsgB%fnVLBnBKgat0>0ty0%-pM0Y(BO35oj?Mb^GL1$|Ap1-PdF z3`ME1$n^Z7D11|VzFYhy)uHvWoHR2ol;i#X2pdVqv)B$D%rEwsvKFlD+)P^Q-AbyeKOX=b4Z!a^!)&~1$0QxafYFfkWL9K1J1wnzLf>xAw1wMqcw z+OIZ6=rTB-|9vZxfCC9EjKhl^9uD_pBySlj^)FAs?L#D04GQ}5lkQce$j+o9*6N7@ z8e9S<2nW)Wt*@J?0dR<o_GNtU@sg4O##|E!+8{BKC zOJl05zp{$KoDH)n=xl1&3my+Rq1BawfcLEpE&>RrHa`B*u6G3&<7>S}RW-;kK)YRe zrx<`PB*5Q^3#J90w&RD#Q}SCduL0_+*G$ukEno(~7nS-62!U0&7#K55;v4+;oFG_a ztA>=~Rb4;e;YJ{61jNQ%C3Mi>8q8qL$=?G3GZ>we%j0UHB(C3fCxNtd4R;;ZZXba3 zEI?E#b{dKNT{RgBh?kXS5PawUXp>z-3>^b`x&>6%2&x+dPg4uH7W;^R{xVw!$S2Ki z4Tp@>z!}sAi%j0M0PTeB{ta6~&sf`692zR^R@^5pp`)>U>~uGb+kUZna&;OhVWxD1 zr!})gUsW_KCo9bekG~3pc7PmDj^m-fQWCG@zJS^Jz6)_Ai#{JC&UH`2NZH}k{5_7| z7pd)t)tB3Ozs0Q@zzte`<%#zESTPAcMli!lAhpvj+KK0~Ib1|&K*So5qJgmSywYx6 zMVbP#TD#tvJDDLySNBeD25m>p5z79mSOUcXPPpU**nNtA>SK=)8X7Vk00C>WEw$EU9bM5L?kAbUy?!QmMP^4S3ZqDur0}c#x?O6jx{l7Y zKYB)tY1kH6Sq!Qtwpj4y`WglB3(&ZYNeJYLB+M}C0MUEG)RQ=z^-|B$L_7S>GDBl{ z?9>Q|@x6Kr-fB5hV`=nkVIQ|8i0NValgQbqs-lKZ1psHW7yu_qglm16h>LEv)Doc{ zNAB`QFl_jm)mPBkc#zv&vYnoPAl}B5uZ7Egrr>psUWr8vDoc_+f)Sq=zQ3C1g9|JB z>g|g%zzz8}zzYnr9Q?Y&!$81~Q$QqWSyXIv`gh7I^xXRqbbGpkx+c`|;=JM7y0scD z>DGe3cxAc4SZ;kI){+siYe})fG#Q|C9|64BJ{^E@Hfv83y_tAYezkTzLTd@S9@IVG zPA9IUokiVBILEKY%0OT0?Ce0&##Du*8$aIik%3tt-Vz(ZKXr{69RmXmfcmR|$(Jy* zK~}T$bBuFFYxpp@AoIBsv@9O20fz>UGiI~Pzy4HpY37C!rX6LB9U~q5MI1wH5k-e zbzSv7^SyJX4vdgG!gU<|oHT+weYrrfmbKc_my7MQkm24yRJ)frZaH8=tYaA4VAG}F zgp~MvC0yXA_3XDD(|$d`NT&G8kfZF1fW9gLMQ+qDGZ!FJz~Sn`~Lo3YeqP(0W~=fY3o9Nl_rA6xPT*e%Rj? z>Wh0HGJ8$|QRxC|9%WP8?tNEBNKEyNk@bu}@!VP~yQ9Xf=OM)R78GbYk+L?{_(Kmu z<5MB!t1tIK_30n;%H|D@|7~$@?j^M&;o?pnWrG2PAa`7KYnIlNPw4@s_~|0ktKGY) z`g6YbYFE5&(y~_6WMo@+)bNp}n@&+fDR*mz;2)s8;9F}msV`&@5picms)OKqnWe6B=z z8|6%$b$f}*>UYg;8I_B(n-mbAEr6&7v&=2i=t6^)zWWh?kVrHaId^@Yz4L4x{~9;! z2v?6t{G`-0S)#zuxO`>rwrXkvVuFyc2zPLiT>C}FiErgU{PodGj*gp_jyw_}35j5> z&yGd{SCqu`N9SK2^fycLu`&0FK1P43fE_ehSCzr~py_t8!IuN2~OXT4Q>}*NM+= z%Q|2lUtR90kM`^KFaOUjB!G$)fmf{}peU-Y0Cur}V6ke}dyl1;WoPn&N-8$DTn|HI z+q3z5KZMS!e05T8-c*p$CqArRlMojd_wGb8sEBR+1oU0M{GM-BKR?fWnQ8a;&T?R0 z2Z53R_4Z^pU>SSjz(qcJumyK7zkE0YG{R!EVawt6juQn|MNbOW`#ZY0lwIhA%3J`+ z0D(t(X_ZA9s4nKQdHVraT<@{^={FZx4Xu?vY^V&XVl*<^`9WbZ@!RWT1!sVBI)ai? zK$|XpI0KZ}3XCBjFj*fBRlQ=*-*dZb9xu%gefweIPGIQ{1Z!Wqot_KQ=XL9$GqApN zSz>xus!tMB^*eim;ur|t_?tt$5pWsmjkB+xLG7yoT6O{!ui*Z-;6$rkwlc<`cBk8+ z+wb?Bmal!=56W3UaH%Da=Xeh&)FuY4f9iY{;)rOtdOzUixmC+Ry>r3FdoYz>K&dD1 zG;pz?i%V60UERLx%N3N2HdPryEr~L5FrMl+eSLS?uZm|Y)vGJgl$4lCwr+`VNxAYh z3lf4odw>m}>7d5ss`x|3moL}++UdV?7O({YOo;PRdlDs+L$8+>L)3bl^t&pO^&8}h uiHWI_$w%H+KKf?E{*0gLu6&>5&;N{UwSpphXR&lK0D-5gpUXO@geCyO3xtXQ literal 0 HcmV?d00001 diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_straight_frenet.png b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/images/terminal_straight_frenet.png new file mode 100644 index 0000000000000000000000000000000000000000..9a36642b2d5451830d70974a84715c7f2d16f9f1 GIT binary patch literal 29125 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 uM literal 0 HcmV?d00001 diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp index a8b7a670c881b..c11839f0356c6 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/scene.hpp @@ -140,6 +140,18 @@ class NormalLaneChange : public LaneChangeBase bool get_lane_change_paths(LaneChangePaths & candidate_paths) const; + bool get_path_using_frenet( + const std::vector & prepare_metrics, + const lane_change::TargetObjects & target_objects, + const std::vector> & sorted_lane_ids, + LaneChangePaths & candidate_paths) const; + + bool get_path_using_path_shifter( + const std::vector & prepare_metrics, + const lane_change::TargetObjects & target_objects, + const std::vector> & sorted_lane_ids, + LaneChangePaths & candidate_paths) const; + bool check_candidate_path_safety( const LaneChangePath & candidate_path, const lane_change::TargetObjects & target_objects) const; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/data.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/data.hpp index 9e6b9d229d2f2..c844b6b218d10 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/data.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/data.hpp @@ -269,6 +269,7 @@ struct CommonData LanesPolygonPtr lanes_polygon_ptr; TransientData transient_data; PathWithLaneId current_lanes_path; + PathWithLaneId target_lanes_path; ModuleType lc_type; Direction direction; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp index 589f2f20ba258..eb07d2f0d3704 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/debug.hpp @@ -39,6 +39,20 @@ struct MetricsDebug double max_lane_changing_length; }; +struct FrenetStateDebug +{ + LaneChangePhaseMetrics prep_metric; + frenet_planner::SamplingParameter sampling_parameter; + double max_lane_changing_length; + + FrenetStateDebug( + LaneChangePhaseMetrics prep_metric, frenet_planner::SamplingParameter sampling_param, + const double max_len) + : prep_metric(prep_metric), sampling_parameter(sampling_param), max_lane_changing_length(max_len) + { + } +}; + struct Debug { std::string module_type; @@ -52,6 +66,7 @@ struct Debug lanelet::ConstLanelets target_lanes; lanelet::ConstLanelets target_backward_lanes; std::vector lane_change_metrics; + std::vector frenet_states; double collision_check_object_debug_lifetime{0.0}; double distance_to_end_of_current_lane{std::numeric_limits::max()}; double distance_to_lane_change_finished{std::numeric_limits::max()}; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp index b25dbc99189e8..f0adcb1d69b42 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp @@ -113,6 +113,13 @@ struct SafetyParameters CollisionCheckParameters collision_check{}; }; +struct FrenetPlannerParameters +{ + bool enable{true}; + double th_yaw_diff_deg{10.0}; + double th_curvature_smoothing{0.1}; +}; + struct TrajectoryParameters { double max_prepare_duration{4.0}; @@ -124,6 +131,7 @@ struct TrajectoryParameters double th_lane_changing_length_diff{0.5}; double min_lane_changing_velocity{5.6}; double lane_changing_decel_factor{0.5}; + double th_prepare_curvature{0.03}; int lon_acc_sampling_num{10}; int lat_acc_sampling_num{10}; LateralAccelerationMap lat_acc_map{}; @@ -151,6 +159,7 @@ struct Parameters CancelParameters cancel{}; DelayParameters delay{}; TerminalPathParameters terminal_path{}; + FrenetPlannerParameters frenet{}; // lane change parameters double backward_lane_length{200.0}; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/path.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/path.hpp index 0fa0a9d977a26..0fa2c6cc8dfbc 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/path.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/path.hpp @@ -19,19 +19,53 @@ #include "autoware/behavior_path_planner_common/turn_signal_decider.hpp" #include "autoware/behavior_path_planner_common/utils/path_shifter/path_shifter.hpp" +#include + #include +#include #include namespace autoware::behavior_path_planner::lane_change { +enum class PathType { ConstantJerk = 0, FrenetPlanner }; + using autoware::behavior_path_planner::TurnSignalInfo; using tier4_planning_msgs::msg::PathWithLaneId; +struct TrajectoryGroup +{ + PathWithLaneId prepare; + PathWithLaneId target_lane_ref_path; + std::vector target_lane_ref_path_dist; + LaneChangePhaseMetrics prepare_metric; + frenet_planner::Trajectory lane_changing; + frenet_planner::FrenetState initial_state; + double max_lane_changing_length{0.0}; + + TrajectoryGroup() = default; + TrajectoryGroup( + PathWithLaneId prepare, PathWithLaneId target_lane_ref_path, + std::vector target_lane_ref_path_dist, LaneChangePhaseMetrics prepare_metric, + frenet_planner::Trajectory lane_changing, frenet_planner::FrenetState initial_state, + const double max_lane_changing_length) + : prepare(std::move(prepare)), + target_lane_ref_path(std::move(target_lane_ref_path)), + target_lane_ref_path_dist(std::move(target_lane_ref_path_dist)), + prepare_metric(prepare_metric), + lane_changing(std::move(lane_changing)), + initial_state(initial_state), + max_lane_changing_length(max_lane_changing_length) + { + } +}; + struct Path { + Info info; PathWithLaneId path; ShiftedPath shifted_path; - Info info; + TrajectoryGroup frenet_path; + PathType type = PathType::ConstantJerk; }; struct Status @@ -39,7 +73,6 @@ struct Status Path lane_change_path; bool is_safe{false}; bool is_valid_path{false}; - double start_distance{0.0}; }; } // namespace autoware::behavior_path_planner::lane_change diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/path.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/path.hpp index 77ba8fe68a653..42586e7b1df92 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/path.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/path.hpp @@ -11,7 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - #ifndef AUTOWARE__BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__PATH_HPP_ #define AUTOWARE__BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__PATH_HPP_ @@ -26,6 +25,7 @@ namespace autoware::behavior_path_planner::utils::lane_change { using behavior_path_planner::LaneChangePath; using behavior_path_planner::lane_change::CommonDataPtr; +using behavior_path_planner::lane_change::TrajectoryGroup; /** * @brief Generates a prepare segment for a lane change maneuver. @@ -98,5 +98,65 @@ LaneChangePath construct_candidate_path( const LaneChangeInfo & lane_change_info, const PathWithLaneId & prepare_segment, const PathWithLaneId & target_lane_reference_path, const std::vector> & sorted_lane_ids); + +/** + * @brief Generates candidate trajectories in the Frenet frame for a lane change maneuver. + * + * This function computes a set of candidate trajectories for the ego vehicle in the Frenet frame, + * based on the provided metrics, target lane reference path, and preparation segments. It ensures + * that the generated trajectories adhere to specified constraints, such as lane boundaries and + * velocity limits, while optimizing for smoothness and curvature. + * + * @param common_data_ptr Shared pointer to CommonData containing route, lane, and transient + * information. + * @param prev_module_path The previous module's path used as a base for preparation segments. + * @param prep_metric Metrics for the preparation phase, including path length and velocity. + * + * @return std::vector A vector of trajectory groups representing + * valid lane change candidates, each containing the prepare segment, target reference path, and + * Frenet trajectory. + */ +std::vector generate_frenet_candidates( + const CommonDataPtr & common_data_ptr, const PathWithLaneId & prev_module_path, + const std::vector & prep_metrics); + +/** + * @brief Constructs a lane change path candidate based on a Frenet trajectory group. + * + * This function generates a candidate lane change path by converting a Frenet trajectory group + * into a shifted path and combining it with a prepare segment. It validates the path's feasibility + * by ensuring yaw differences are within allowable thresholds and calculates lane change + * information, such as acceleration, velocity, and duration. + * + * @param trajectory_group A Frenet trajectory group containing the prepared path and Frenet + * trajectory data. + * @param common_data_ptr Shared pointer to CommonData providing parameters and constraints for lane + * changes. + * @param sorted_lane_ids A vector of sorted lane IDs used to update the lane IDs in the path. + * + * @return std::optional The constructed candidate lane change path if valid, or + * std::nullopt if the path is not feasible. + * + * @throws std::logic_error If the yaw difference exceeds the threshold, or other critical errors + * occur. + */ +std::optional get_candidate_path( + const TrajectoryGroup & trajectory_group, const CommonDataPtr & common_data_ptr, + const std::vector> & sorted_lane_ids); + +/** + * @brief Appends the target lane reference path to the candidate lane change path. + * + * This function extends the lane change candidate path by appending points from the + * target lane reference path beyond the lane change end position. The appending process + * is constrained by a curvature threshold to ensure smooth transitions and avoid sharp turns. + * + * @param frenet_candidate The candidate lane change path to which the target reference path is + * appended. This includes the lane change path and associated Frenet trajectory data. + * @param th_curvature_smoothing A threshold for the allowable curvature during the extension + * process. Points with curvature exceeding this threshold are excluded. + */ +void append_target_ref_to_candidate(LaneChangePath & frenet_candidate, const double th_curvature); } // namespace autoware::behavior_path_planner::utils::lane_change + #endif // AUTOWARE__BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__PATH_HPP_ diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/utils.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/utils.hpp index 69362994dbbac..422c392cac462 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/utils.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/utils/utils.hpp @@ -24,6 +24,8 @@ #include #include +#include +#include #include #include @@ -56,6 +58,7 @@ using behavior_path_planner::lane_change::LCParamPtr; using behavior_path_planner::lane_change::ModuleType; using behavior_path_planner::lane_change::PathSafetyStatus; using behavior_path_planner::lane_change::TargetLaneLeadingObjects; +using behavior_path_planner::lane_change::TrajectoryGroup; using geometry_msgs::msg::Point; using geometry_msgs::msg::Pose; using geometry_msgs::msg::Twist; @@ -69,9 +72,27 @@ bool is_mandatory_lane_change(const ModuleType lc_type); void set_prepare_velocity( PathWithLaneId & prepare_segment, const double current_velocity, const double prepare_velocity); -std::vector replaceWithSortedIds( - const std::vector & original_lane_ids, - const std::vector> & sorted_lane_ids); +/** + * @brief Replaces the current lane IDs with a sorted set of IDs based on a predefined mapping. + * + * This function checks if the current lane IDs match the previously processed lane IDs. + * If they do, it returns the previously sorted IDs for efficiency. Otherwise, it matches + * the current lane IDs to the appropriate sorted IDs from the provided mapping and updates + * the cached values. + * + * @param current_lane_ids The current lane IDs to be replaced or verified. + * @param sorted_lane_ids A vector of sorted lane ID groups, each representing a predefined + * order of IDs for specific conditions. + * @param prev_lane_ids Reference to the previously processed lane IDs for caching purposes. + * @param prev_sorted_lane_ids Reference to the previously sorted lane IDs for caching purposes. + * + * @return std::vector The sorted lane IDs if a match is found, or the original + * `current_lane_ids` if no match exists. + */ +std::vector replace_with_sorted_ids( + const std::vector & current_lane_ids, + const std::vector> & sorted_lane_ids, std::vector & prev_lane_ids, + std::vector & prev_sorted_lane_ids); std::vector> get_sorted_lane_ids(const CommonDataPtr & common_data_ptr); @@ -432,5 +453,24 @@ std::vector> convert_to_predicted_paths( * @return true if the pose is within the target or target neighbor polygons, false otherwise. */ bool is_valid_start_point(const lane_change::CommonDataPtr & common_data_ptr, const Pose & pose); + +/** + * @brief Converts a lane change frenet candidate into a predicted path for the ego vehicle. + * + * This function generates a predicted path based on the provided Frenet candidate, + * simulating the vehicle's trajectory during the preparation and lane-changing phases. + * It interpolates poses and velocities over the duration of the prediction, considering + * the ego vehicle's initial conditions and the candidate's trajectory data. + * + * @param common_data_ptr Shared pointer to CommonData containing parameters and ego vehicle state. + * @param frenet_candidate A Frenet trajectory group representing the lane change candidate. + * @param deceleration_sampling_num Unused parameter for deceleration sampling count. + * + * @return std::vector The predicted path as a series of stamped poses + * with associated velocities over the prediction time. + */ +std::vector convert_to_predicted_path( + const CommonDataPtr & common_data_ptr, const lane_change::TrajectoryGroup & frenet_candidate, + [[maybe_unused]] const size_t deceleration_sampling_num); } // namespace autoware::behavior_path_planner::utils::lane_change #endif // AUTOWARE__BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__UTILS_HPP_ diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/package.xml b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/package.xml index fad98ecf8f8e1..cf7600556080e 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/package.xml +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/package.xml @@ -23,6 +23,7 @@ autoware_behavior_path_planner autoware_behavior_path_planner_common + autoware_frenet_planner autoware_motion_utils autoware_rtc_interface autoware_universe_utils diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp index ec000b8fee97c..06a9d505f90ad 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp @@ -63,6 +63,8 @@ LCParamPtr LaneChangeModuleManager::set_params(rclcpp::Node * node, const std::s getOrDeclareParameter(*node, parameter("trajectory.min_lane_changing_velocity")); p.trajectory.lane_changing_decel_factor = getOrDeclareParameter(*node, parameter("trajectory.lane_changing_decel_factor")); + p.trajectory.th_prepare_curvature = + getOrDeclareParameter(*node, parameter("trajectory.th_prepare_curvature")); p.trajectory.lon_acc_sampling_num = getOrDeclareParameter(*node, parameter("trajectory.lon_acc_sampling_num")); p.trajectory.lat_acc_sampling_num = @@ -213,6 +215,12 @@ LCParamPtr LaneChangeModuleManager::set_params(rclcpp::Node * node, const std::s p.delay.th_parked_vehicle_shift_ratio = getOrDeclareParameter( *node, parameter("delay_lane_change.th_parked_vehicle_shift_ratio")); + // trajectory generation near terminal using frenet planner + p.frenet.enable = getOrDeclareParameter(*node, parameter("frenet.enable")); + p.frenet.th_yaw_diff_deg = getOrDeclareParameter(*node, parameter("frenet.th_yaw_diff")); + p.frenet.th_curvature_smoothing = + getOrDeclareParameter(*node, parameter("frenet.th_curvature_smoothing")); + // lane change cancel p.cancel.enable_on_prepare_phase = getOrDeclareParameter(*node, parameter("cancel.enable_on_prepare_phase")); @@ -338,6 +346,8 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectortrajectory.max_longitudinal_acc); updateParam( parameters, ns + "lane_changing_decel_factor", p->trajectory.lane_changing_decel_factor); + updateParam( + parameters, ns + "th_prepare_curvature", p->trajectory.th_prepare_curvature); int longitudinal_acc_sampling_num = 0; updateParam(parameters, ns + "lon_acc_sampling_num", longitudinal_acc_sampling_num); if (longitudinal_acc_sampling_num > 0) { @@ -356,6 +366,14 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectortrajectory.th_lane_changing_length_diff); } + { + const std::string ns = "lane_change.frenet."; + updateParam(parameters, ns + "enable", p->frenet.enable); + updateParam(parameters, ns + "th_yaw_diff", p->frenet.th_yaw_diff_deg); + updateParam( + parameters, ns + "th_curvature_smoothing", p->frenet.th_curvature_smoothing); + } + { const std::string ns = "lane_change.safety_check.lane_expansion."; updateParam(parameters, ns + "left_offset", p->safety.lane_expansion_left_offset); diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp index 88f58debb886a..7748795851865 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp @@ -28,7 +28,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -36,8 +39,11 @@ #include #include +#include + #include #include +#include #include #include @@ -104,6 +110,9 @@ void NormalLaneChange::update_lanes(const bool is_approved) common_data_ptr_->current_lanes_path = route_handler_ptr->getCenterLinePath(current_lanes, 0.0, std::numeric_limits::max()); + common_data_ptr_->target_lanes_path = + route_handler_ptr->getCenterLinePath(target_lanes, 0.0, std::numeric_limits::max()); + common_data_ptr_->lanes_ptr->target_neighbor = utils::lane_change::get_target_neighbor_lanes( *route_handler_ptr, current_lanes, common_data_ptr_->lc_type); @@ -232,8 +241,6 @@ void NormalLaneChange::updateLaneChangeStatus() // Update status status_.is_valid_path = found_valid_path; status_.is_safe = found_safe_path; - - status_.start_distance = common_data_ptr_->transient_data.target_lanes_ego_arc.length; status_.lane_change_path.path.header = getRouteHeader(); } @@ -1124,15 +1131,92 @@ bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) } const auto & current_lanes = get_current_lanes(); - const auto & target_lanes = get_target_lanes(); - const auto sorted_lane_ids = utils::lane_change::get_sorted_lane_ids(common_data_ptr_); const auto target_objects = get_target_objects(filtered_objects_, current_lanes); const auto prepare_phase_metrics = get_prepare_metrics(); + const auto sorted_lane_ids = utils::lane_change::get_sorted_lane_ids(common_data_ptr_); + if ( + common_data_ptr_->lc_param_ptr->frenet.enable && + common_data_ptr_->transient_data.is_ego_near_current_terminal_start) { + return get_path_using_frenet( + prepare_phase_metrics, target_objects, sorted_lane_ids, candidate_paths); + } + + return get_path_using_path_shifter( + prepare_phase_metrics, target_objects, sorted_lane_ids, candidate_paths); +} + +bool NormalLaneChange::get_path_using_frenet( + const std::vector & prepare_metrics, + const lane_change::TargetObjects & target_objects, + const std::vector> & sorted_lane_ids, + LaneChangePaths & candidate_paths) const +{ + stop_watch_.tic("frenet_candidates"); + constexpr auto found_safe_path = true; + const auto frenet_candidates = utils::lane_change::generate_frenet_candidates( + common_data_ptr_, prev_module_output_.path, prepare_metrics); + RCLCPP_DEBUG( + logger_, "Generated %lu candidate paths in %2.2f[us]", frenet_candidates.size(), + stop_watch_.toc("frenet_candidates")); + + candidate_paths.reserve(frenet_candidates.size()); + lane_change_debug_.frenet_states.clear(); + lane_change_debug_.frenet_states.reserve(frenet_candidates.size()); + for (const auto & frenet_candidate : frenet_candidates) { + lane_change_debug_.frenet_states.emplace_back( + frenet_candidate.prepare_metric, frenet_candidate.lane_changing.sampling_parameter, + frenet_candidate.max_lane_changing_length); + + std::optional candidate_path_opt; + try { + candidate_path_opt = + utils::lane_change::get_candidate_path(frenet_candidate, common_data_ptr_, sorted_lane_ids); + } catch (const std::exception & e) { + RCLCPP_DEBUG(logger_, "%s", e.what()); + } + + if (!candidate_path_opt) { + continue; + } + + try { + if (check_candidate_path_safety(*candidate_path_opt, target_objects)) { + RCLCPP_DEBUG( + logger_, "Found safe path after %lu candidate(s). Total time: %2.2f[us]", + frenet_candidates.size(), stop_watch_.toc("frenet_candidates")); + utils::lane_change::append_target_ref_to_candidate( + *candidate_path_opt, common_data_ptr_->lc_param_ptr->frenet.th_curvature_smoothing); + candidate_paths.push_back(*candidate_path_opt); + return found_safe_path; + } + } catch (const std::exception & e) { + RCLCPP_DEBUG(logger_, "%s", e.what()); + } + + // appending all paths affect performance + if (candidate_paths.empty()) { + candidate_paths.push_back(*candidate_path_opt); + } + } + + RCLCPP_DEBUG( + logger_, "No safe path after %lu candidate(s). Total time: %2.2f[us]", frenet_candidates.size(), + stop_watch_.toc("frenet_candidates")); + return !found_safe_path; +} + +bool NormalLaneChange::get_path_using_path_shifter( + const std::vector & prepare_metrics, + const lane_change::TargetObjects & target_objects, + const std::vector> & sorted_lane_ids, + LaneChangePaths & candidate_paths) const +{ + const auto & target_lanes = get_target_lanes(); candidate_paths.reserve( - prepare_phase_metrics.size() * lane_change_parameters_->trajectory.lat_acc_sampling_num); + prepare_metrics.size() * lane_change_parameters_->trajectory.lat_acc_sampling_num); const bool only_tl = getStopTime() >= lane_change_parameters_->th_stop_time; const auto dist_to_next_regulatory_element = @@ -1151,7 +1235,7 @@ bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) return lc_diff > lane_change_parameters_->trajectory.th_lane_changing_length_diff; }; - for (const auto & prep_metric : prepare_phase_metrics) { + for (const auto & prep_metric : prepare_metrics) { const auto debug_print = [&](const std::string & s) { RCLCPP_DEBUG( logger_, "%s | prep_time: %.5f | lon_acc: %.5f | prep_len: %.5f", s.c_str(), @@ -1195,7 +1279,7 @@ bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) prepare_segment, common_data_ptr_->get_ego_speed(), prep_metric.velocity); for (const auto & lc_metric : lane_changing_metrics) { - debug_metrics.lc_metrics.push_back({lc_metric, -1}); + debug_metrics.lc_metrics.emplace_back(lc_metric, -1); const auto debug_print_lat = [&](const std::string & s) { RCLCPP_DEBUG( @@ -1218,7 +1302,7 @@ bool NormalLaneChange::get_lane_change_paths(LaneChangePaths & candidate_paths) } candidate_paths.push_back(candidate_path); - debug_metrics.lc_metrics.back().second = candidate_paths.size() - 1; + debug_metrics.lc_metrics.back().second = static_cast(candidate_paths.size()) - 1; try { if (check_candidate_path_safety(candidate_path, target_objects)) { diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp index ef899cceea0d4..bf0af0d133dc7 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/markers.cpp @@ -73,6 +73,34 @@ MarkerArray showAllValidLaneChangePath( marker.points.push_back(point.point.pose.position); } + const auto & info = lc_path.info; + auto text_marker = createDefaultMarker( + "map", current_time, ns_with_idx, ++id, visualization_msgs::msg::Marker::TEXT_VIEW_FACING, + createMarkerScale(0.1, 0.1, 0.8), colors::yellow()); + const auto prep_idx = points.size() / 4; + text_marker.pose = points.at(prep_idx).point.pose; + text_marker.pose.position.z += 2.0; + text_marker.text = fmt::format( + "vel: {vel:.3f}[m/s] | lon_acc: {lon_acc:.3f}[m/s2] | t: {time:.3f}[s] | L: {length:.3f}[m]", + fmt::arg("vel", info.velocity.prepare), + fmt::arg("lon_acc", info.longitudinal_acceleration.prepare), + fmt::arg("time", info.duration.prepare), fmt::arg("length", info.length.prepare)); + marker_array.markers.push_back(text_marker); + + const auto lc_idx = points.size() / 2; + text_marker.id = ++id; + text_marker.pose = points.at(lc_idx).point.pose; + text_marker.text = fmt::format( + "type: {type} | vel: {vel:.3f}[m/s] | lon_acc: {lon_acc:.3f}[m/s2] | lat_acc: " + "{lat_acc:.3f}[m/s2] | t: " + "{time:.3f}[s] | L: {length:.3f}[m]", + fmt::arg("type", magic_enum::enum_name(lc_path.type)), + fmt::arg("vel", info.velocity.lane_changing), + fmt::arg("lon_acc", info.longitudinal_acceleration.lane_changing), + fmt::arg("lat_acc", info.lateral_acceleration), fmt::arg("time", info.duration.lane_changing), + fmt::arg("length", info.length.lane_changing)); + marker_array.markers.push_back(text_marker); + marker_array.markers.push_back(marker); } return marker_array; @@ -171,43 +199,78 @@ MarkerArray ShowLaneChangeMetricsInfo( const Debug & debug_data, const geometry_msgs::msg::Pose & pose) { MarkerArray marker_array; - if (debug_data.lane_change_metrics.empty()) { - return marker_array; - } auto text_marker = createDefaultMarker( "map", rclcpp::Clock{RCL_ROS_TIME}.now(), "sampling_metrics", 0, Marker::TEXT_VIEW_FACING, createMarkerScale(0.6, 0.6, 0.6), colors::yellow()); text_marker.pose = autoware::universe_utils::calcOffsetPose(pose, 10.0, 15.0, 0.0); - text_marker.text = - fmt::format("{:<12}", "") + fmt::format("{:^18}|", "lat_accel[m/s2]") + - fmt::format("{:^18}|", "lon_accel[m/s2]") + fmt::format("{:^17}|", "velocity[m/s]") + - fmt::format("{:^15}|", "duration[s]") + fmt::format("{:^15}|", "length[m]") + - fmt::format("{:^20}|", "max_length_th[m]") + fmt::format("{:^15}\n", "path_index"); - for (const auto & metrics : debug_data.lane_change_metrics) { - text_marker.text += fmt::format("{:-<190}\n", ""); - const auto & p_m = metrics.prep_metric; - text_marker.text += - fmt::format("{:<17}", "prep_metrics:") + fmt::format("{:^10.3f}", p_m.lat_accel) + - fmt::format("{:^21.3f}", p_m.actual_lon_accel) + fmt::format("{:^12.3f}", p_m.velocity) + - fmt::format("{:^15.3f}", p_m.duration) + fmt::format("{:^15.3f}", p_m.length) + - fmt::format("{:^17.3f}", metrics.max_prepare_length) + fmt::format("{:^15}\n", "-"); - text_marker.text += fmt::format("{:<20}\n", "lc_metrics:"); - for (const auto & lc_m : metrics.lc_metrics) { - const auto & metric = lc_m.first; - const auto path_index = lc_m.second < 0 ? "-" : std::to_string(lc_m.second); - text_marker.text += fmt::format("{:<15}", "") + fmt::format("{:^10.3f}", metric.lat_accel) + - fmt::format("{:^21.3f}", metric.actual_lon_accel) + - fmt::format("{:^12.3f}", metric.velocity) + - fmt::format("{:^15.3f}", metric.duration) + - fmt::format("{:^15.3f}", metric.length) + - fmt::format("{:^17.3f}", metrics.max_lane_changing_length) + - fmt::format("{:^15}\n", path_index); + if (!debug_data.lane_change_metrics.empty()) { + text_marker.text = + fmt::format("{:<12}", "") + fmt::format("{:^18}|", "lat_accel[m/s2]") + + fmt::format("{:^18}|", "lon_accel[m/s2]") + fmt::format("{:^17}|", "velocity[m/s]") + + fmt::format("{:^15}|", "duration[s]") + fmt::format("{:^15}|", "length[m]") + + fmt::format("{:^20}|", "max_length_th[m]") + fmt::format("{:^15}\n", "path_index"); + for (const auto & metrics : debug_data.lane_change_metrics) { + text_marker.text += fmt::format("{:-<190}\n", ""); + const auto & p_m = metrics.prep_metric; + text_marker.text += + fmt::format("{:<17}", "prep_metrics:") + fmt::format("{:^10.3f}", p_m.lat_accel) + + fmt::format("{:^21.3f}", p_m.actual_lon_accel) + fmt::format("{:^12.3f}", p_m.velocity) + + fmt::format("{:^15.3f}", p_m.duration) + fmt::format("{:^15.3f}", p_m.length) + + fmt::format("{:^17.3f}", metrics.max_prepare_length) + fmt::format("{:^15}\n", "-"); + text_marker.text += fmt::format("{:<20}\n", "lc_metrics:"); + for (const auto & lc_m : metrics.lc_metrics) { + const auto & metric = lc_m.first; + const auto path_index = lc_m.second < 0 ? "-" : std::to_string(lc_m.second); + text_marker.text += fmt::format("{:<15}", "") + fmt::format("{:^10.3f}", metric.lat_accel) + + fmt::format("{:^21.3f}", metric.actual_lon_accel) + + fmt::format("{:^12.3f}", metric.velocity) + + fmt::format("{:^15.3f}", metric.duration) + + fmt::format("{:^15.3f}", metric.length) + + fmt::format("{:^17.3f}", metrics.max_lane_changing_length) + + fmt::format("{:^15}\n", path_index); + } } + marker_array.markers.push_back(text_marker); + } + + if (!debug_data.frenet_states.empty()) { + text_marker.text = fmt::format("{:<12}", "") + fmt::format("{:^18}|", "lon_accel[m/s2]") + + fmt::format("{:^17}|", "lon_vel[m/s]") + + fmt::format("{:^15}|", "duration[s]") + fmt::format("{:^15}|", "length[m]") + + fmt::format("{:^17}|", "lat_accel[m/s2]") + + fmt::format("{:^15}|", "lat_vel[m/s2]") + fmt::format("{:^15}|", "s[m]") + + fmt::format("{:^15}|", "d[m]") + fmt::format("{:^20}\n", "max_length_th[m]"); + for (const auto & metrics : debug_data.frenet_states) { + text_marker.text += fmt::format("{:-<250}\n", ""); + const auto & p_m = metrics.prep_metric; + const auto max_len = metrics.max_lane_changing_length; + text_marker.text += + fmt::format("{:<17}", "prep_metrics:") + fmt::format("{:^13.3f}", p_m.actual_lon_accel) + + fmt::format("{:^15.3f}", p_m.velocity) + fmt::format("{:^15.3f}", p_m.duration) + + fmt::format("{:^12.3f}", p_m.length) + + fmt::format("{:^13}", "") + // Empty string for lat_accel + fmt::format("{:^13}", "") + // Empty string for lat_vel + fmt::format("{:^15}", "") + // Empty string for s + fmt::format("{:^15}", "") + // Empty string for d // Empty string for d + fmt::format("{:^20.3f}\n", max_len); // Empty string for max_length_t + const auto & lc_m = metrics.sampling_parameter.target_state; // Assuming lc_metric exists + const auto duration = metrics.sampling_parameter.target_duration; + text_marker.text += + fmt::format("{:<17}", "frenet_state:") + + fmt::format("{:^15.3f}", lc_m.longitudinal_acceleration) + + fmt::format("{:^13.3f}", lc_m.longitudinal_velocity) + fmt::format("{:^17.3f}", duration) + + fmt::format("{:^10.3f}", lc_m.position.s) + + fmt::format("{:^19.3f}", lc_m.lateral_acceleration) + + fmt::format("{:^10.3f}", lc_m.lateral_velocity) + + fmt::format("{:^18.3f}", lc_m.position.s) + fmt::format("{:^15.3f}", lc_m.position.d) + + fmt::format("{:^16.3f}\n", max_len); // Empty string for max_length_t + } + + marker_array.markers.push_back(text_marker); } - marker_array.markers.push_back(text_marker); return marker_array; } diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/path.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/path.cpp index 44ee1624f0f51..df45da3f08fa1 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/path.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/path.cpp @@ -15,17 +15,22 @@ #include "autoware/behavior_path_lane_change_module/utils/path.hpp" #include "autoware/behavior_path_lane_change_module/structs/data.hpp" +#include "autoware/behavior_path_lane_change_module/utils/calculation.hpp" #include "autoware/behavior_path_lane_change_module/utils/utils.hpp" #include "autoware/behavior_path_planner_common/utils/path_utils.hpp" #include "autoware/behavior_path_planner_common/utils/utils.hpp" #include #include +#include #include +#include #include #include #include +#include + #include #include #include @@ -42,8 +47,22 @@ using autoware::behavior_path_planner::lane_change::LCParamPtr; using autoware::behavior_path_planner::LaneChangePhaseMetrics; using autoware::behavior_path_planner::ShiftLine; +using autoware::behavior_path_planner::lane_change::TrajectoryGroup; +using autoware::frenet_planner::FrenetState; +using autoware::frenet_planner::SamplingParameters; +using autoware::route_handler::Direction; +using autoware::sampler_common::FrenetPoint; +using autoware::sampler_common::transform::Spline2D; +using autoware::universe_utils::LineString2d; +using autoware::universe_utils::Point2d; using geometry_msgs::msg::Pose; +template +T sign(const Direction direction) +{ + return static_cast(direction == Direction::LEFT ? 1.0 : -1.0); +} + double calc_resample_interval( const double lane_changing_length, const double lane_changing_velocity) { @@ -53,7 +72,7 @@ double calc_resample_interval( lane_changing_length / min_resampling_points, lane_changing_velocity * resampling_dt); } -PathWithLaneId get_reference_path_from_target_Lane( +PathWithLaneId get_reference_path_from_target_lane( const CommonDataPtr & common_data_ptr, const Pose & lane_changing_start_pose, const double lane_changing_length, const double resample_interval) { @@ -146,11 +165,197 @@ std::optional exceed_yaw_threshold( } return std::nullopt; } + +Spline2D init_reference_spline(const std::vector & target_lanes_ref_path) +{ + std::vector xs; + std::vector ys; + xs.reserve(target_lanes_ref_path.size()); + ys.reserve(target_lanes_ref_path.size()); + for (const auto & p : target_lanes_ref_path) { + xs.push_back(p.point.pose.position.x); + ys.push_back(p.point.pose.position.y); + } + + return {xs, ys}; +} + +FrenetState init_frenet_state( + const FrenetPoint & start_position, const LaneChangePhaseMetrics & prepare_metrics) +{ + FrenetState initial_state; + initial_state.position = start_position; + initial_state.longitudinal_velocity = prepare_metrics.velocity; + initial_state.lateral_velocity = + 0.0; // TODO(Maxime): this can be sampled if we want but it would impact the LC duration + initial_state.longitudinal_acceleration = prepare_metrics.sampled_lon_accel; + initial_state.lateral_acceleration = prepare_metrics.lat_accel; + return initial_state; +} + +std::optional init_sampling_parameters( + const CommonDataPtr & common_data_ptr, const LaneChangePhaseMetrics & prepare_metrics, + const FrenetState & initial_state, const Spline2D & ref_spline, const Pose & lc_start_pose) +{ + const auto & trajectory = common_data_ptr->lc_param_ptr->trajectory; + const auto min_lc_vel = trajectory.min_lane_changing_velocity; + const auto [min_lateral_acc, max_lateral_acc] = + trajectory.lat_acc_map.find(std::max(min_lc_vel, prepare_metrics.velocity)); + const auto duration = autoware::motion_utils::calc_shift_time_from_jerk( + std::abs(initial_state.position.d), trajectory.lateral_jerk, max_lateral_acc); + const auto final_velocity = + std::max(min_lc_vel, prepare_metrics.velocity + prepare_metrics.sampled_lon_accel * duration); + const auto lc_length = duration * (prepare_metrics.velocity + final_velocity) * 0.5; + const auto target_s = initial_state.position.s + lc_length; + const auto initial_yaw = tf2::getYaw(lc_start_pose.orientation); + const auto target_lat_vel = + (1.0 - ref_spline.curvature(target_s + 1e-3) * initial_state.position.d) * + std::tan(initial_yaw - ref_spline.yaw(target_s)); + + if (std::isnan(target_lat_vel)) { + return std::nullopt; + } + + SamplingParameters sampling_parameters; + const auto & safety = common_data_ptr->lc_param_ptr->safety; + sampling_parameters.resolution = safety.collision_check.prediction_time_resolution; + sampling_parameters.parameters.emplace_back(); + sampling_parameters.parameters.back().target_duration = duration; + sampling_parameters.parameters.back().target_state.position = {target_s, 0.0}; + // TODO(Maxime): not sure if we should use curvature at initial or target s + sampling_parameters.parameters.back().target_state.lateral_velocity = + sign(common_data_ptr->direction) * target_lat_vel; + sampling_parameters.parameters.back().target_state.lateral_acceleration = 0.0; + sampling_parameters.parameters.back().target_state.longitudinal_velocity = final_velocity; + sampling_parameters.parameters.back().target_state.longitudinal_acceleration = + prepare_metrics.sampled_lon_accel; + return sampling_parameters; +} + +std::vector calc_curvatures( + const std::vector & points, const Pose & current_pose) +{ + const auto nearest_segment_idx = + autoware::motion_utils::findNearestSegmentIndex(points, current_pose.position); + + // Ignore all path points behind ego vehicle. + if (points.size() <= nearest_segment_idx + 2) { + return {}; + } + + std::vector curvatures; + curvatures.reserve(points.size() - nearest_segment_idx + 2); + for (const auto & [p1, p2, p3] : ranges::views::zip( + points | ranges::views::drop(nearest_segment_idx), + points | ranges::views::drop(nearest_segment_idx + 1), + points | ranges::views::drop(nearest_segment_idx + 2))) { + const auto point1 = autoware::universe_utils::getPoint(p1); + const auto point2 = autoware::universe_utils::getPoint(p2); + const auto point3 = autoware::universe_utils::getPoint(p3); + + curvatures.push_back(autoware::universe_utils::calcCurvature(point1, point2, point3)); + } + + return curvatures; +} + +double calc_average_curvature(const std::vector & curvatures) +{ + const auto filter_zeros = [](const auto & k) { return k != 0.0; }; + auto filtered_k = curvatures | ranges::views::filter(filter_zeros); + if (filtered_k.empty()) { + return 0.0; + } + const auto sums_of_curvatures = [](float sum, const double k) { return sum + std::abs(k); }; + const auto sum_of_k = ranges::accumulate(filtered_k, 0.0, sums_of_curvatures); + const auto count_k = static_cast(ranges::distance(filtered_k)); + return sum_of_k / count_k; +} + +LineString2d get_linestring_bound(const lanelet::ConstLanelets & lanes, const Direction direction) +{ + LineString2d line_string; + const auto & get_bound = [&](const lanelet::ConstLanelet & lane) { + return (direction == Direction::LEFT) ? lane.leftBound2d() : lane.rightBound2d(); + }; + + const auto reserve_size = ranges::accumulate( + lanes, 0UL, + [&](auto sum, const lanelet::ConstLanelet & lane) { return sum + get_bound(lane).size(); }); + line_string.reserve(reserve_size); + for (const auto & lane : lanes) { + ranges::for_each(get_bound(lane), [&line_string](const auto & point) { + boost::geometry::append(line_string, Point2d(point.x(), point.y())); + }); + } + return line_string; +} + +Point2d shift_point(const Point2d & p1, const Point2d & p2, const double offset) +{ + // Calculate the perpendicular vector + double dx = p2.x() - p1.x(); + double dy = p2.y() - p1.y(); + double length = std::sqrt(dx * dx + dy * dy); + + // Normalize and find the perpendicular direction + double nx = -dy / length; + double ny = dx / length; + + return {p1.x() + nx * offset, p1.y() + ny * offset}; +} + +bool check_out_of_bound_paths( + const CommonDataPtr & common_data_ptr, const std::vector & lane_changing_poses, + const LineString2d & lane_boundary, const Direction direction) +{ + const auto distance = (0.5 * common_data_ptr->bpp_param_ptr->vehicle_width + 0.1); + const auto offset = sign(direction) * distance; // invert direction + if (lane_changing_poses.size() <= 2) { + return true; // Remove candidates with insufficient poses + } + + LineString2d path_ls; + path_ls.reserve(lane_changing_poses.size()); + + const auto segments = lane_changing_poses | ranges::views::sliding(2); + ranges::for_each(segments | ranges::views::drop(1), [&](const auto & segment) { + const auto & p1 = segment[0].position; + const auto & p2 = segment[1].position; + boost::geometry::append(path_ls, shift_point({p2.x, p2.y}, {p1.x, p1.y}, offset)); + }); + + return boost::geometry::disjoint(path_ls, lane_boundary); // Remove if disjoint +} + +double calc_limit(const CommonDataPtr & common_data_ptr, const Pose & lc_end_pose) +{ + const auto dist_to_target_end = std::invoke([&]() { + if (common_data_ptr->lanes_ptr->target_lane_in_goal_section) { + return autoware::motion_utils::calcSignedArcLength( + common_data_ptr->target_lanes_path.points, lc_end_pose.position, + common_data_ptr->route_handler_ptr->getGoalPose().position); + } + return autoware::motion_utils::calcSignedArcLength( + common_data_ptr->target_lanes_path.points, lc_end_pose.position, + common_data_ptr->target_lanes_path.points.back().point.pose.position); + }); + + // v2 = u2 + 2ad + // u = sqrt(2ad) + return std::clamp( + std::sqrt( + std::abs(2.0 * common_data_ptr->bpp_param_ptr->min_acc * std::max(dist_to_target_end, 0.0))), + common_data_ptr->lc_param_ptr->trajectory.min_lane_changing_velocity, + common_data_ptr->bpp_param_ptr->max_vel); +} + }; // namespace namespace autoware::behavior_path_planner::utils::lane_change { using behavior_path_planner::lane_change::CommonDataPtr; +using behavior_path_planner::lane_change::PathType; bool get_prepare_segment( const CommonDataPtr & common_data_ptr, const PathWithLaneId & prev_module_path, @@ -187,7 +392,17 @@ bool get_prepare_segment( throw std::logic_error("lane change start is behind target lanelet!"); } - return true; + const auto curvatures = calc_curvatures(prepare_segment.points, common_data_ptr->get_ego_pose()); + + // curvatures may be empty if ego is near the terminal start of the path. + if (curvatures.empty()) { + return true; + } + + const auto average_curvature = calc_average_curvature(curvatures); + + RCLCPP_DEBUG(get_logger(), "average curvature: %.3f", average_curvature); + return average_curvature <= common_data_ptr->lc_param_ptr->trajectory.th_prepare_curvature; } LaneChangePath get_candidate_path( @@ -205,7 +420,7 @@ LaneChangePath get_candidate_path( } const auto & lc_start_pose = prep_segment.points.back().point.pose; - const auto target_lane_reference_path = get_reference_path_from_target_Lane( + const auto target_lane_reference_path = get_reference_path_from_target_lane( common_data_ptr, lc_start_pose, lc_metric.length, resample_interval); if (target_lane_reference_path.points.empty()) { @@ -259,10 +474,14 @@ LaneChangePath construct_candidate_path( throw std::logic_error("Lane change end idx not found on target path."); } + std::vector prev_ids; + std::vector prev_sorted_ids; for (size_t i = 0; i < shifted_path.path.points.size(); ++i) { auto & point = shifted_path.path.points.at(i); if (i < *lc_end_idx_opt) { - point.lane_ids = replaceWithSortedIds(point.lane_ids, sorted_lane_ids); + const auto & current_ids = point.lane_ids; + point.lane_ids = + replace_with_sorted_ids(current_ids, sorted_lane_ids, prev_ids, prev_sorted_ids); point.point.longitudinal_velocity_mps = std::min( point.point.longitudinal_velocity_mps, static_cast(terminal_lane_changing_velocity)); continue; @@ -286,7 +505,251 @@ LaneChangePath construct_candidate_path( candidate_path.path = utils::combinePath(prepare_segment, shifted_path.path); candidate_path.shifted_path = shifted_path; candidate_path.info = lane_change_info; + candidate_path.type = PathType::ConstantJerk; return candidate_path; } + +std::vector generate_frenet_candidates( + const CommonDataPtr & common_data_ptr, const PathWithLaneId & prev_module_path, + const std::vector & prep_metrics) +{ + std::vector trajectory_groups; + universe_utils::StopWatch sw; + + const auto & transient_data = common_data_ptr->transient_data; + const auto & current_lanes = common_data_ptr->lanes_ptr->current; + const auto & target_lanes = common_data_ptr->lanes_ptr->target; + const auto direction = common_data_ptr->direction; + const auto current_lane_boundary = get_linestring_bound(current_lanes, direction); + + for (const auto & metric : prep_metrics) { + PathWithLaneId prepare_segment; + try { + if (!utils::lane_change::get_prepare_segment( + common_data_ptr, prev_module_path, metric.length, prepare_segment)) { + RCLCPP_DEBUG(get_logger(), "Reject: failed to get valid prepare segment!"); + continue; + } + } catch (const std::exception & e) { + RCLCPP_WARN(get_logger(), "%s", e.what()); + break; + } + const auto lc_start_pose = prepare_segment.points.back().point.pose; + + const auto dist_to_end_from_lc_start = + calculation::calc_dist_from_pose_to_terminal_end( + common_data_ptr, target_lanes, lc_start_pose) - + common_data_ptr->lc_param_ptr->lane_change_finish_judge_buffer; + const auto max_lc_len = transient_data.lane_changing_length.max; + const auto max_lane_changing_length = std::min(dist_to_end_from_lc_start, max_lc_len); + + constexpr auto resample_interval = 0.5; + const auto target_lane_reference_path = get_reference_path_from_target_lane( + common_data_ptr, lc_start_pose, max_lane_changing_length, resample_interval); + if (target_lane_reference_path.points.empty()) { + continue; + } + + std::vector target_ref_path_sums{0.0}; + target_ref_path_sums.reserve(target_lane_reference_path.points.size() - 1); + double ref_s = 0.0; + for (auto it = target_lane_reference_path.points.begin(); + std::next(it) != target_lane_reference_path.points.end(); ++it) { + ref_s += universe_utils::calcDistance2d(*it, *std::next(it)); + target_ref_path_sums.push_back(ref_s); + } + + const auto reference_spline = init_reference_spline(target_lane_reference_path.points); + + const auto initial_state = init_frenet_state( + reference_spline.frenet({lc_start_pose.position.x, lc_start_pose.position.y}), metric); + + RCLCPP_DEBUG( + get_logger(), "Initial state [s=%2.2f, d=%2.2f, s'=%2.2f, d'=%2.2f, s''=%2.2f, d''=%2.2f]", + initial_state.position.s, initial_state.position.d, initial_state.longitudinal_velocity, + initial_state.lateral_velocity, initial_state.longitudinal_acceleration, + initial_state.lateral_acceleration); + + const auto sampling_parameters_opt = init_sampling_parameters( + common_data_ptr, metric, initial_state, reference_spline, lc_start_pose); + + if (!sampling_parameters_opt) { + continue; + } + + auto frenet_trajectories = frenet_planner::generateTrajectories( + reference_spline, initial_state, *sampling_parameters_opt); + + trajectory_groups.reserve(trajectory_groups.size() + frenet_trajectories.size()); + for (const auto & traj : frenet_trajectories) { + if (!trajectory_groups.empty()) { + const auto diff = std::abs( + traj.frenet_points.back().s - + trajectory_groups.back().lane_changing.frenet_points.back().s); + if (diff < common_data_ptr->lc_param_ptr->trajectory.th_lane_changing_length_diff) { + continue; + } + } + + const auto out_of_bound = + check_out_of_bound_paths(common_data_ptr, traj.poses, current_lane_boundary, direction); + + if (out_of_bound) { + continue; + } + + trajectory_groups.emplace_back( + prepare_segment, target_lane_reference_path, target_ref_path_sums, metric, traj, + initial_state, max_lane_changing_length); + } + } + + const auto limit_vel = [&](TrajectoryGroup & group) { + const auto max_vel = calc_limit(common_data_ptr, group.lane_changing.poses.back()); + for (auto & vel : group.lane_changing.longitudinal_velocities) { + vel = std::clamp(vel, 0.0, max_vel); + } + }; + + ranges::for_each(trajectory_groups, limit_vel); + + ranges::sort(trajectory_groups, [&](const auto & p1, const auto & p2) { + return calc_average_curvature(p1.lane_changing.curvatures) < + calc_average_curvature(p2.lane_changing.curvatures); + }); + + return trajectory_groups; +} + +std::optional get_candidate_path( + const TrajectoryGroup & trajectory_group, const CommonDataPtr & common_data_ptr, + const std::vector> & sorted_lane_ids) +{ + if (trajectory_group.lane_changing.frenet_points.empty()) { + return std::nullopt; + } + + ShiftedPath shifted_path; + std::vector prev_ids; + std::vector prev_sorted_ids; + const auto & lane_changing_candidate = trajectory_group.lane_changing; + const auto & target_lane_ref_path = trajectory_group.target_lane_ref_path; + const auto & prepare_segment = trajectory_group.prepare; + const auto & prepare_metric = trajectory_group.prepare_metric; + const auto & initial_state = trajectory_group.initial_state; + const auto & target_ref_sums = trajectory_group.target_lane_ref_path_dist; + auto zipped_candidates = ranges::views::zip( + lane_changing_candidate.poses, lane_changing_candidate.frenet_points, + lane_changing_candidate.longitudinal_velocities, lane_changing_candidate.lateral_velocities, + lane_changing_candidate.curvatures); + + shifted_path.path.points.reserve(zipped_candidates.size()); + shifted_path.shift_length.reserve(zipped_candidates.size()); + for (const auto & [pose, frenet_point, longitudinal_velocity, lateral_velocity, curvature] : + zipped_candidates) { + // Find the reference index + const auto & s = frenet_point.s; + auto ref_i_itr = std::find_if( + target_ref_sums.begin(), target_ref_sums.end(), + [s](const double ref_s) { return ref_s > s; }); + auto ref_i = std::distance(target_ref_sums.begin(), ref_i_itr); + + PathPointWithLaneId point; + point.point.pose = pose; + point.point.longitudinal_velocity_mps = static_cast(longitudinal_velocity); + point.point.lateral_velocity_mps = static_cast(lateral_velocity); + point.point.heading_rate_rps = static_cast(curvature); + point.point.pose.position.z = target_lane_ref_path.points[ref_i].point.pose.position.z; + const auto & current_ids = target_lane_ref_path.points[ref_i].lane_ids; + point.lane_ids = + replace_with_sorted_ids(current_ids, sorted_lane_ids, prev_ids, prev_sorted_ids); + + // Add to shifted path + shifted_path.shift_length.push_back(frenet_point.d); + shifted_path.path.points.push_back(point); + } + + if (shifted_path.path.points.empty()) { + return std::nullopt; + } + + for (auto & point : shifted_path.path.points) { + point.point.longitudinal_velocity_mps = std::min( + point.point.longitudinal_velocity_mps, + static_cast(shifted_path.path.points.back().point.longitudinal_velocity_mps)); + } + + const auto th_yaw_diff_deg = common_data_ptr->lc_param_ptr->frenet.th_yaw_diff_deg; + if ( + const auto yaw_diff_opt = exceed_yaw_threshold( + prepare_segment, shifted_path.path, autoware::universe_utils::deg2rad(th_yaw_diff_deg))) { + const auto yaw_diff_deg = autoware::universe_utils::rad2deg(yaw_diff_opt.value()); + const auto err_msg = fmt::format( + "Excessive yaw difference {yaw_diff:2.2f}[deg]. The threshold is {th_yaw_diff:2.2f}[deg].", + fmt::arg("yaw_diff", yaw_diff_deg), fmt::arg("th_yaw_diff", th_yaw_diff_deg)); + throw std::logic_error(err_msg); + } + + LaneChangeInfo info; + info.longitudinal_acceleration = { + prepare_metric.actual_lon_accel, lane_changing_candidate.longitudinal_accelerations.front()}; + info.velocity = {prepare_metric.velocity, initial_state.longitudinal_velocity}; + info.duration = { + prepare_metric.duration, lane_changing_candidate.sampling_parameter.target_duration}; + info.length = {prepare_metric.length, lane_changing_candidate.lengths.back()}; + info.lane_changing_start = prepare_segment.points.back().point.pose; + info.lane_changing_end = lane_changing_candidate.poses.back(); + + ShiftLine sl; + + sl.start = lane_changing_candidate.poses.front(); + sl.end = lane_changing_candidate.poses.back(); + sl.start_shift_length = 0.0; + sl.end_shift_length = initial_state.position.d; + sl.start_idx = 0UL; + sl.end_idx = shifted_path.shift_length.size() - 1; + + info.shift_line = sl; + info.terminal_lane_changing_velocity = lane_changing_candidate.longitudinal_velocities.back(); + info.lateral_acceleration = lane_changing_candidate.lateral_accelerations.front(); + + LaneChangePath candidate_path; + candidate_path.path = utils::combinePath(prepare_segment, shifted_path.path); + candidate_path.info = info; + candidate_path.shifted_path = shifted_path; + candidate_path.frenet_path = trajectory_group; + candidate_path.type = PathType::FrenetPlanner; + + return candidate_path; +} + +void append_target_ref_to_candidate( + LaneChangePath & frenet_candidate, const double th_curvature_smoothing) +{ + const auto & target_lane_ref_path = frenet_candidate.frenet_path.target_lane_ref_path.points; + const auto & lc_end_pose = frenet_candidate.info.lane_changing_end; + const auto lc_end_idx = + motion_utils::findNearestIndex(target_lane_ref_path, lc_end_pose.position); + auto & candidate_path = frenet_candidate.path.points; + if (target_lane_ref_path.size() <= lc_end_idx + 2) { + return; + } + const auto add_size = target_lane_ref_path.size() - (lc_end_idx + 1); + candidate_path.reserve(candidate_path.size() + add_size); + const auto & points = target_lane_ref_path; + for (const auto & [p2, p3] : ranges::views::zip( + points | ranges::views::drop(lc_end_idx + 1), + points | ranges::views::drop(lc_end_idx + 2))) { + const auto point1 = autoware::universe_utils::getPoint(candidate_path.back().point.pose); + const auto point2 = autoware::universe_utils::getPoint(p2); + const auto point3 = autoware::universe_utils::getPoint(p3); + const auto curvature = + std::abs(autoware::universe_utils::calcCurvature(point1, point2, point3)); + if (curvature < th_curvature_smoothing) { + candidate_path.push_back(p2); + } + } + candidate_path.push_back(target_lane_ref_path.back()); +} } // namespace autoware::behavior_path_planner::utils::lane_change diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/utils.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/utils.cpp index 9360435891632..9002270185847 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/utils.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/utils/utils.cpp @@ -24,12 +24,18 @@ #include "autoware/object_recognition_utils/predicted_path_utils.hpp" #include "autoware/universe_utils/math/unit_conversion.hpp" +// for the geometry types +#include +#include +// for the svg mapper #include #include #include #include #include #include +#include +#include #include #include #include @@ -40,9 +46,10 @@ #include #include -#include - +#include #include +#include +#include #include #include @@ -64,9 +71,11 @@ namespace autoware::behavior_path_planner::utils::lane_change { using autoware::route_handler::RouteHandler; using autoware::universe_utils::LineString2d; +using autoware::universe_utils::Point2d; using autoware::universe_utils::Polygon2d; using autoware_perception_msgs::msg::ObjectClassification; using autoware_perception_msgs::msg::PredictedObjects; +using behavior_path_planner::lane_change::PathType; using geometry_msgs::msg::Pose; using tier4_planning_msgs::msg::PathWithLaneId; @@ -382,18 +391,26 @@ std::vector> get_sorted_lane_ids(const CommonDataPtr & comm return sorted_lane_ids; } -std::vector replaceWithSortedIds( - const std::vector & original_lane_ids, - const std::vector> & sorted_lane_ids) +std::vector replace_with_sorted_ids( + const std::vector & current_lane_ids, + const std::vector> & sorted_lane_ids, std::vector & prev_lane_ids, + std::vector & prev_sorted_lane_ids) { - for (const auto original_id : original_lane_ids) { + if (current_lane_ids == prev_lane_ids) { + return prev_sorted_lane_ids; + } + + for (const auto original_id : current_lane_ids) { for (const auto & sorted_id : sorted_lane_ids) { if (std::find(sorted_id.cbegin(), sorted_id.cend(), original_id) != sorted_id.cend()) { - return sorted_id; + prev_lane_ids = current_lane_ids; + prev_sorted_lane_ids = sorted_id; + return prev_sorted_lane_ids; } } } - return original_lane_ids; + + return current_lane_ids; } CandidateOutput assignToCandidate( @@ -475,6 +492,7 @@ std::vector convert_to_predicted_path( 0.5 * lane_changing_acceleration * delta_t * delta_t + offset; const auto pose = autoware::motion_utils::calcInterpolatedPose( path.points, vehicle_pose_frenet.length + length); + predicted_path.emplace_back(t, pose, velocity); } @@ -1127,6 +1145,10 @@ std::vector> convert_to_predicted_paths( const auto acc_resolution = (min_acc - lane_changing_acc) / static_cast(sampling_num); const auto ego_predicted_path = [&](size_t n) { + if (lane_change_path.type == PathType::FrenetPlanner) { + return convert_to_predicted_path( + common_data_ptr, lane_change_path.frenet_path, deceleration_sampling_num); + } auto acc = lane_changing_acc + static_cast(n) * acc_resolution; return utils::lane_change::convert_to_predicted_path(common_data_ptr, lane_change_path, acc); }; @@ -1135,6 +1157,48 @@ std::vector> convert_to_predicted_paths( ranges::to(); } +std::vector convert_to_predicted_path( + const CommonDataPtr & common_data_ptr, const lane_change::TrajectoryGroup & frenet_candidate, + [[maybe_unused]] const size_t deceleration_sampling_num) +{ + const auto initial_velocity = common_data_ptr->get_ego_speed(); + const auto prepare_time = frenet_candidate.prepare_metric.duration; + const auto resolution = + common_data_ptr->lc_param_ptr->safety.collision_check.prediction_time_resolution; + const auto prepare_acc = frenet_candidate.prepare_metric.sampled_lon_accel; + std::vector predicted_path; + const auto & path = frenet_candidate.prepare.points; + const auto & vehicle_pose = common_data_ptr->get_ego_pose(); + const auto & bpp_param_ptr = common_data_ptr->bpp_param_ptr; + const auto nearest_seg_idx = + autoware::motion_utils::findFirstNearestSegmentIndexWithSoftConstraints( + path, vehicle_pose, bpp_param_ptr->ego_nearest_dist_threshold, + bpp_param_ptr->ego_nearest_yaw_threshold); + + const auto vehicle_pose_frenet = + convertToFrenetPoint(path, vehicle_pose.position, nearest_seg_idx); + + for (double t = 0.0; t < prepare_time; t += resolution) { + const auto velocity = + std::clamp(initial_velocity + prepare_acc * t, 0.0, frenet_candidate.prepare_metric.velocity); + const auto length = initial_velocity * t + 0.5 * prepare_acc * t * t; + const auto pose = + autoware::motion_utils::calcInterpolatedPose(path, vehicle_pose_frenet.length + length); + predicted_path.emplace_back(t, pose, velocity); + } + + const auto & poses = frenet_candidate.lane_changing.poses; + const auto & velocities = frenet_candidate.lane_changing.longitudinal_velocities; + const auto & times = frenet_candidate.lane_changing.times; + + for (const auto [t, pose, velocity] : + ranges::views::zip(times, poses, velocities) | ranges::views::drop(1)) { + predicted_path.emplace_back(prepare_time + t, pose, velocity); + } + + return predicted_path; +} + bool is_valid_start_point(const lane_change::CommonDataPtr & common_data_ptr, const Pose & pose) { const lanelet::BasicPoint2d lc_start_point(pose.position.x, pose.position.y); diff --git a/planning/sampling_based_planner/autoware_frenet_planner/src/frenet_planner/frenet_planner.cpp b/planning/sampling_based_planner/autoware_frenet_planner/src/frenet_planner/frenet_planner.cpp index cab4acfbb8556..54d4bc2e90714 100644 --- a/planning/sampling_based_planner/autoware_frenet_planner/src/frenet_planner/frenet_planner.cpp +++ b/planning/sampling_based_planner/autoware_frenet_planner/src/frenet_planner/frenet_planner.cpp @@ -197,6 +197,15 @@ void calculateCartesian( trajectory.longitudinal_accelerations.push_back(0.0); trajectory.lateral_accelerations.push_back(0.0); } + for (auto i = 0UL; i < trajectory.points.size(); ++i) { + geometry_msgs::msg::Pose pose; + pose.position.x = trajectory.points[i].x(); + pose.position.y = trajectory.points[i].y(); + pose.position.z = 0.0; + pose.orientation = + autoware::universe_utils::createQuaternionFromRPY(0.0, 0.0, trajectory.yaws[i]); + trajectory.poses.push_back(pose); + } } } From 96998925ad72498c77e0e6a52f5132bb2cb8a92b Mon Sep 17 00:00:00 2001 From: Yukinari Hisaki <42021302+yhisaki@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:23:20 +0900 Subject: [PATCH 08/61] fix(learning_based_vehicle_model): fix clang-diagnostic-delete-abstract-non-virtual-dtor (#9506) Signed-off-by: Y.Hisaki --- .../learning_based_vehicle_model/src/interconnected_model.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/simulator/learning_based_vehicle_model/src/interconnected_model.cpp b/simulator/learning_based_vehicle_model/src/interconnected_model.cpp index d2fef15aa4e88..e495aceb8da9c 100644 --- a/simulator/learning_based_vehicle_model/src/interconnected_model.cpp +++ b/simulator/learning_based_vehicle_model/src/interconnected_model.cpp @@ -79,8 +79,7 @@ void InterconnectedModel::addSubmodel( std::tuple submodel_desc) { const auto [lib_path, param_path, class_name] = submodel_desc; - auto new_model = new SimplePyModel(lib_path, param_path, class_name); - submodels.push_back(std::unique_ptr(new_model)); + submodels.emplace_back(std::make_unique(lib_path, param_path, class_name)); } void InterconnectedModel::initState(std::vector new_state) From 215cae29afaa5923e8c74e216d99e6549980990d Mon Sep 17 00:00:00 2001 From: Ismet Atabay <56237550+ismetatabay@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:31:53 +0300 Subject: [PATCH 09/61] feat(remaining_distance_time_calculator): skip calculation during parking (#9013) Signed-off-by: ismetatabay --- .../README.md | 1 + ...aining_distance_time_calculator.launch.xml | 2 ++ ...emaining_distance_time_calculator_node.cpp | 21 ++++++++++++++++++- ...emaining_distance_time_calculator_node.hpp | 5 +++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/planning/autoware_remaining_distance_time_calculator/README.md b/planning/autoware_remaining_distance_time_calculator/README.md index 694c6764de91c..c227b73b87448 100644 --- a/planning/autoware_remaining_distance_time_calculator/README.md +++ b/planning/autoware_remaining_distance_time_calculator/README.md @@ -8,6 +8,7 @@ This package aims to provide mission remaining distance and remaining time calcu - The calculations are activated once we have a route planned for a mission in Autoware. - The calculations are triggered timely based on the `update_rate` parameter. +- The calculations are skipped if the scenario is PARKING, and the remaining time and distance values are set to 0.0. ### Module Parameters diff --git a/planning/autoware_remaining_distance_time_calculator/launch/remaining_distance_time_calculator.launch.xml b/planning/autoware_remaining_distance_time_calculator/launch/remaining_distance_time_calculator.launch.xml index cfb456c57ca41..be7898bdd8913 100644 --- a/planning/autoware_remaining_distance_time_calculator/launch/remaining_distance_time_calculator.launch.xml +++ b/planning/autoware_remaining_distance_time_calculator/launch/remaining_distance_time_calculator.launch.xml @@ -4,6 +4,7 @@ + @@ -13,6 +14,7 @@ + diff --git a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp index 383e85731604e..7932a2531185f 100644 --- a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp +++ b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp @@ -37,6 +37,7 @@ RemainingDistanceTimeCalculatorNode::RemainingDistanceTimeCalculatorNode( : Node("remaining_distance_time_calculator", options), is_graph_ready_{false}, has_received_route_{false}, + has_received_scenario_{false}, velocity_limit_{99.99}, remaining_distance_{0.0}, remaining_time_{0.0} @@ -57,6 +58,8 @@ RemainingDistanceTimeCalculatorNode::RemainingDistanceTimeCalculatorNode( sub_planning_velocity_ = create_subscription( "/planning/scenario_planning/current_max_velocity", qos_transient_local, std::bind(&RemainingDistanceTimeCalculatorNode::on_velocity_limit, this, _1)); + sub_scenario_ = this->create_subscription( + "~/input/scenario", 1, std::bind(&RemainingDistanceTimeCalculatorNode::on_scenario, this, _1)); pub_mission_remaining_distance_time_ = create_publisher( "~/output/mission_remaining_distance_time", @@ -100,9 +103,25 @@ void RemainingDistanceTimeCalculatorNode::on_velocity_limit( } } +void RemainingDistanceTimeCalculatorNode::on_scenario( + const tier4_planning_msgs::msg::Scenario::ConstSharedPtr & msg) +{ + scenario_ = msg; + has_received_scenario_ = true; +} + void RemainingDistanceTimeCalculatorNode::on_timer() { - if (is_graph_ready_ && has_received_route_) { + if (!has_received_scenario_) { + return; + } + + // check if the scenario is parking or not + if (scenario_->current_scenario == tier4_planning_msgs::msg::Scenario::PARKING) { + remaining_distance_ = 0.0; + remaining_time_ = 0.0; + publish_mission_remaining_distance_time(); + } else if (is_graph_ready_ && has_received_route_) { calculate_remaining_distance(); calculate_remaining_time(); publish_mission_remaining_distance_time(); diff --git a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp index d6c900af4dfed..b7af8861bf524 100644 --- a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp +++ b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,7 @@ class RemainingDistanceTimeCalculatorNode : public rclcpp::Node rclcpp::Subscription::SharedPtr sub_map_; rclcpp::Subscription::SharedPtr sub_odometry_; rclcpp::Subscription::SharedPtr sub_planning_velocity_; + rclcpp::Subscription::SharedPtr sub_scenario_; rclcpp::Publisher::SharedPtr pub_mission_remaining_distance_time_; @@ -75,7 +77,9 @@ class RemainingDistanceTimeCalculatorNode : public rclcpp::Node geometry_msgs::msg::Pose current_vehicle_pose_; geometry_msgs::msg::Vector3 current_vehicle_velocity_; geometry_msgs::msg::Pose goal_pose_; + tier4_planning_msgs::msg::Scenario::ConstSharedPtr scenario_; bool has_received_route_; + bool has_received_scenario_; double velocity_limit_; double remaining_distance_; @@ -90,6 +94,7 @@ class RemainingDistanceTimeCalculatorNode : public rclcpp::Node void on_route(const LaneletRoute::ConstSharedPtr & msg); void on_map(const HADMapBin::ConstSharedPtr & msg); void on_velocity_limit(const VelocityLimit::ConstSharedPtr & msg); + void on_scenario(const tier4_planning_msgs::msg::Scenario::ConstSharedPtr & msg); /** * @brief calculate mission remaining distance From 36b74c23311d677c06600a55d37bfed36e01d163 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:35:13 +0900 Subject: [PATCH 10/61] =?UTF-8?q?feat(autoware=5Fobject=5Fmerger):=20tier4?= =?UTF-8?q?=5Fdebug=5Fmsgs=20changed=20to=20autoware=5Finternal=5Fdebug=5F?= =?UTF-8?q?msgs=20in=20fil=E2=80=A6=20(#9893)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files perception/autoware_object_merger Signed-off-by: vish0012 Co-authored-by: Taekjin LEE --- .../src/object_association_merger_node.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perception/autoware_object_merger/src/object_association_merger_node.cpp b/perception/autoware_object_merger/src/object_association_merger_node.cpp index 0e2b88f4aa566..40bdd0a7d6938 100644 --- a/perception/autoware_object_merger/src/object_association_merger_node.cpp +++ b/perception/autoware_object_merger/src/object_association_merger_node.cpp @@ -235,9 +235,9 @@ void ObjectAssociationMergerNode::objectsCallback( merged_object_pub_->publish(output_msg); published_time_publisher_->publish_if_subscribed(merged_object_pub_, output_msg.header.stamp); // publish processing time - processing_time_publisher_->publish( + processing_time_publisher_->publish( "debug/cyclic_time_ms", stop_watch_ptr_->toc("cyclic_time", true)); - processing_time_publisher_->publish( + processing_time_publisher_->publish( "debug/processing_time_ms", stop_watch_ptr_->toc("processing_time", true)); } } // namespace autoware::object_merger From 9c0e183d25c1a76a8091f7c210c95ac32f94d5f4 Mon Sep 17 00:00:00 2001 From: Kyoichi Sugahara <32741405+kyoichi-sugahara@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:50:46 +0900 Subject: [PATCH 11/61] feat(lane_change_module): add update paramter function for non defined paramters (#9887) * feat(lane_change_module): add new parameters for collision check and delay lane change functionality Signed-off-by: Kyoichi Sugahara * feat(lane_change_module): add validation for longitudinal and lateral acceleration sampling parameters Signed-off-by: Kyoichi Sugahara * feat(lane_change): update parameter handling and add lateral acceleration mapping Signed-off-by: Kyoichi Sugahara --------- Signed-off-by: Kyoichi Sugahara --- .../src/manager.cpp | 125 +++++++++++++++++- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp index 06a9d505f90ad..07b05ab0ea131 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp @@ -324,10 +324,12 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectorlane_change_finish_judge_buffer); updateParam( parameters, ns + "enable_stopped_vehicle_buffer", p->enable_stopped_vehicle_buffer); - updateParam( parameters, ns + "finish_judge_lateral_threshold", p->th_finish_judge_lateral_diff); updateParam(parameters, ns + "publish_debug_marker", p->publish_debug_marker); + updateParam( + parameters, ns + "min_length_for_turn_signal_activation", + p->min_length_for_turn_signal_activation); } { @@ -338,8 +340,7 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectortrajectory.min_prepare_duration); updateParam(parameters, ns + "lateral_jerk", p->trajectory.lateral_jerk); updateParam( - parameters, ns + ".min_lane_changing_velocity", p->trajectory.min_lane_changing_velocity); - // longitudinal acceleration + parameters, ns + "min_lane_changing_velocity", p->trajectory.min_lane_changing_velocity); updateParam( parameters, ns + "min_longitudinal_acc", p->trajectory.min_longitudinal_acc); updateParam( @@ -352,12 +353,22 @@ void LaneChangeModuleManager::updateModuleParams(const std::vector(parameters, ns + "lon_acc_sampling_num", longitudinal_acc_sampling_num); if (longitudinal_acc_sampling_num > 0) { p->trajectory.lon_acc_sampling_num = longitudinal_acc_sampling_num; + } else { + RCLCPP_WARN_ONCE( + node_->get_logger(), + "Parameter 'lon_acc_sampling_num' is not updated because the value (%d) is not positive", + longitudinal_acc_sampling_num); } int lateral_acc_sampling_num = 0; updateParam(parameters, ns + "lat_acc_sampling_num", lateral_acc_sampling_num); if (lateral_acc_sampling_num > 0) { p->trajectory.lat_acc_sampling_num = lateral_acc_sampling_num; + } else { + RCLCPP_WARN_ONCE( + node_->get_logger(), + "Parameter 'lat_acc_sampling_num' is not updated because the value (%d) is not positive", + lateral_acc_sampling_num); } updateParam( @@ -380,6 +391,57 @@ void LaneChangeModuleManager::updateModuleParams(const std::vector(parameters, ns + "right_offset", p->safety.lane_expansion_right_offset); } + { + const std::string ns = "lane_change.lateral_acceleration."; + std::vector velocity = p->trajectory.lat_acc_map.base_vel; + std::vector min_values = p->trajectory.lat_acc_map.base_min_acc; + std::vector max_values = p->trajectory.lat_acc_map.base_max_acc; + + updateParam>(parameters, ns + "velocity", velocity); + updateParam>(parameters, ns + "min_values", min_values); + updateParam>(parameters, ns + "max_values", max_values); + if ( + velocity.size() >= 2 && velocity.size() == min_values.size() && + velocity.size() == max_values.size()) { + LateralAccelerationMap lat_acc_map; + for (size_t i = 0; i < velocity.size(); ++i) { + lat_acc_map.add(velocity.at(i), min_values.at(i), max_values.at(i)); + } + p->trajectory.lat_acc_map = lat_acc_map; + } else { + RCLCPP_WARN_ONCE( + node_->get_logger(), + "Mismatched size for lateral acceleration. Expected size: %lu, but velocity: %lu, " + "min_values: %lu, max_values: %lu", + std::max(2ul, velocity.size()), velocity.size(), min_values.size(), max_values.size()); + } + } + + { + const std::string ns = "lane_change.collision_check."; + updateParam( + parameters, ns + "enable_for_prepare_phase.general_lanes", + p->safety.collision_check.enable_for_prepare_phase_in_general_lanes); + updateParam( + parameters, ns + "enable_for_prepare_phase.intersection", + p->safety.collision_check.enable_for_prepare_phase_in_intersection); + updateParam( + parameters, ns + "enable_for_prepare_phase.turns", + p->safety.collision_check.enable_for_prepare_phase_in_turns); + updateParam( + parameters, ns + "check_current_lanes", p->safety.collision_check.check_current_lane); + updateParam( + parameters, ns + "check_other_lanes", p->safety.collision_check.check_other_lanes); + updateParam( + parameters, ns + "use_all_predicted_paths", + p->safety.collision_check.use_all_predicted_paths); + updateParam( + parameters, ns + "prediction_time_resolution", + p->safety.collision_check.prediction_time_resolution); + updateParam( + parameters, ns + "yaw_diff_threshold", p->safety.collision_check.th_yaw_diff); + } + { const std::string ns = "lane_change.target_object."; updateParam(parameters, ns + "car", p->safety.target_object_types.check_car); @@ -407,6 +469,50 @@ void LaneChangeModuleManager::updateModuleParams(const std::vector(parameters, ns + "stop_time", p->th_stop_time); } + auto update_rss_params = [¶meters](const std::string & prefix, auto & params) { + using autoware::universe_utils::updateParam; + updateParam( + parameters, prefix + "longitudinal_distance_min_threshold", + params.longitudinal_distance_min_threshold); + updateParam( + parameters, prefix + "longitudinal_velocity_delta_time", + params.longitudinal_velocity_delta_time); + updateParam( + parameters, prefix + "expected_front_deceleration", params.front_vehicle_deceleration); + updateParam( + parameters, prefix + "expected_rear_deceleration", params.rear_vehicle_deceleration); + updateParam( + parameters, prefix + "rear_vehicle_reaction_time", params.rear_vehicle_reaction_time); + updateParam( + parameters, prefix + "rear_vehicle_safety_time_margin", + params.rear_vehicle_safety_time_margin); + updateParam( + parameters, prefix + "lateral_distance_max_threshold", params.lateral_distance_max_threshold); + }; + + update_rss_params("lane_change.safety_check.execution.", p->safety.rss_params); + update_rss_params("lane_change.safety_check.parked.", p->safety.rss_params_for_parked); + update_rss_params("lane_change.safety_check.cancel.", p->safety.rss_params_for_abort); + update_rss_params("lane_change.safety_check.stuck.", p->safety.rss_params_for_stuck); + + { + const std::string ns = "lane_change.delay_lane_change."; + updateParam(parameters, ns + "enable", p->delay.enable); + updateParam( + parameters, ns + "check_only_parked_vehicle", p->delay.check_only_parked_vehicle); + updateParam( + parameters, ns + "min_road_shoulder_width", p->delay.min_road_shoulder_width); + updateParam( + parameters, ns + "th_parked_vehicle_shift_ratio", p->delay.th_parked_vehicle_shift_ratio); + } + + { + const std::string ns = "lane_change.terminal_path."; + updateParam(parameters, ns + "enable", p->terminal_path.enable); + updateParam(parameters, ns + "disable_near_goal", p->terminal_path.disable_near_goal); + updateParam(parameters, ns + "stop_at_boundary", p->terminal_path.stop_at_boundary); + } + { const std::string ns = "lane_change.cancel."; bool enable_on_prepare_phase = true; @@ -424,6 +530,18 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectorcancel.enable_on_lane_changing_phase = enable_on_lane_changing_phase; } + int deceleration_sampling_num = 0; + updateParam(parameters, ns + "deceleration_sampling_num", deceleration_sampling_num); + if (deceleration_sampling_num > 0) { + p->cancel.deceleration_sampling_num = deceleration_sampling_num; + } else { + RCLCPP_WARN_ONCE( + node_->get_logger(), + "Parameter 'deceleration_sampling_num' is not updated because the value (%d) is not " + "positive", + deceleration_sampling_num); + } + updateParam(parameters, ns + "delta_time", p->cancel.delta_time); updateParam(parameters, ns + "duration", p->cancel.duration); updateParam(parameters, ns + "max_lateral_jerk", p->cancel.max_lateral_jerk); @@ -431,6 +549,7 @@ void LaneChangeModuleManager::updateModuleParams(const std::vector( parameters, ns + "unsafe_hysteresis_threshold", p->cancel.th_unsafe_hysteresis); } + std::for_each(observers_.begin(), observers_.end(), [&p](const auto & observer) { if (!observer.expired()) observer.lock()->updateModuleParams(p); }); From 6e0e6c09f422063d72a727229bf34daffef279a9 Mon Sep 17 00:00:00 2001 From: Yuki TAKAGI <141538661+yuki-takagi-66@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:23:19 +0900 Subject: [PATCH 12/61] fix(behavior_velocity_planner_common): fix unregister process (#9913) Signed-off-by: yuki-takagi-66 --- .../behavior_velocity_planner_common/scene_module_interface.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp index d8d640a078267..a891b011dbab8 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp @@ -228,6 +228,7 @@ class SceneModuleManagerInterface auto itr = scene_modules_.begin(); while (itr != scene_modules_.end()) { if (isModuleExpired(*itr)) { + registered_module_id_set_.erase((*itr)->getModuleId()); itr = scene_modules_.erase(itr); } else { itr++; From 5f88055f48c885733cfa6217c811a17a21470a36 Mon Sep 17 00:00:00 2001 From: Kirill Glinskiy <56448851+PurplePegasuss@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:10:07 +0300 Subject: [PATCH 13/61] docs(autoware_mission_planner): added odometry input in README.md (#7281) added odometry input in README.md Signed-off-by: Ryohsuke Mitsudome --- planning/autoware_mission_planner/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/planning/autoware_mission_planner/README.md b/planning/autoware_mission_planner/README.md index b5993d0106add..720ecd976f65f 100644 --- a/planning/autoware_mission_planner/README.md +++ b/planning/autoware_mission_planner/README.md @@ -53,6 +53,7 @@ It distributes route requests and planning results according to current MRM oper | `input/vector_map` | autoware_map_msgs/msg/LaneletMapBin | vector map of Lanelet2 | | `input/modified_goal` | geometry_msgs/PoseWithUuidStamped | modified goal pose | | `input/operation_mode_state` | autoware_adapi_v1_msgs/OperationModeState | operation mode state | +| `input/odometry` | nav_msgs/msg/Odometry | vehicle odometry | ### Publications From 951b1df19373a57c813ece9dd15dcd6a6f6bb0cf Mon Sep 17 00:00:00 2001 From: cyn-liu <104069308+cyn-liu@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:22:37 +0800 Subject: [PATCH 14/61] fix(autoware_tensorrt_yolox): modify tensorrt_yolox_node name (#9156) Signed-off-by: liu cui --- .../launch/multiple_yolox.launch.xml | 16 ++++++++++++++++ .../launch/yolox_s_plus_opt.launch.xml | 6 ++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/perception/autoware_tensorrt_yolox/launch/multiple_yolox.launch.xml b/perception/autoware_tensorrt_yolox/launch/multiple_yolox.launch.xml index a7952b12414b1..606fd1299cf35 100644 --- a/perception/autoware_tensorrt_yolox/launch/multiple_yolox.launch.xml +++ b/perception/autoware_tensorrt_yolox/launch/multiple_yolox.launch.xml @@ -11,34 +11,50 @@ + + + + + + + + + + + + + + + + diff --git a/perception/autoware_tensorrt_yolox/launch/yolox_s_plus_opt.launch.xml b/perception/autoware_tensorrt_yolox/launch/yolox_s_plus_opt.launch.xml index 0096a219c8573..6d40905d78127 100644 --- a/perception/autoware_tensorrt_yolox/launch/yolox_s_plus_opt.launch.xml +++ b/perception/autoware_tensorrt_yolox/launch/yolox_s_plus_opt.launch.xml @@ -1,6 +1,8 @@ + + @@ -15,13 +17,13 @@ - + - + From bc0dcccbec3131cea2bde0761f811f971f0f10e4 Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <78338830+maxime-clem@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:25:04 +0900 Subject: [PATCH 15/61] test(external_velocity_limit_selector): add node test (#8944) add node smoke test Signed-off-by: Maxime CLEMENT --- .../CMakeLists.txt | 7 + .../package.xml | 1 + .../external_velocity_limit_selector_node.cpp | 1 - ...nal_velocity_limit_selector_node_launch.py | 178 ++++++++++++++++++ 4 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 planning/autoware_external_velocity_limit_selector/test/test_external_velocity_limit_selector_node_launch.py diff --git a/planning/autoware_external_velocity_limit_selector/CMakeLists.txt b/planning/autoware_external_velocity_limit_selector/CMakeLists.txt index ca758d1262b48..aa8d07d91135e 100644 --- a/planning/autoware_external_velocity_limit_selector/CMakeLists.txt +++ b/planning/autoware_external_velocity_limit_selector/CMakeLists.txt @@ -21,6 +21,13 @@ rclcpp_components_register_node(external_velocity_limit_selector_node EXECUTABLE external_velocity_limit_selector ) +if(BUILD_TESTING) + add_launch_test( + test/test_external_velocity_limit_selector_node_launch.py + TIMEOUT "30" + ) +endif() + ament_auto_package(INSTALL_TO_SHARE launch config diff --git a/planning/autoware_external_velocity_limit_selector/package.xml b/planning/autoware_external_velocity_limit_selector/package.xml index b75a4fab72d7c..5bfd3fa936d50 100644 --- a/planning/autoware_external_velocity_limit_selector/package.xml +++ b/planning/autoware_external_velocity_limit_selector/package.xml @@ -28,6 +28,7 @@ ament_lint_auto autoware_lint_common + ros_testing ament_cmake diff --git a/planning/autoware_external_velocity_limit_selector/src/external_velocity_limit_selector_node.cpp b/planning/autoware_external_velocity_limit_selector/src/external_velocity_limit_selector_node.cpp index cf42763fc6b60..cc2b134900a31 100644 --- a/planning/autoware_external_velocity_limit_selector/src/external_velocity_limit_selector_node.cpp +++ b/planning/autoware_external_velocity_limit_selector/src/external_velocity_limit_selector_node.cpp @@ -14,7 +14,6 @@ #include "autoware/external_velocity_limit_selector/external_velocity_limit_selector_node.hpp" -#include #include #include #include diff --git a/planning/autoware_external_velocity_limit_selector/test/test_external_velocity_limit_selector_node_launch.py b/planning/autoware_external_velocity_limit_selector/test/test_external_velocity_limit_selector_node_launch.py new file mode 100644 index 0000000000000..1c7e882fbc81f --- /dev/null +++ b/planning/autoware_external_velocity_limit_selector/test/test_external_velocity_limit_selector_node_launch.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 + +# Copyright 2024 TIER IV, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import unittest + +from ament_index_python import get_package_share_directory +import launch +from launch.actions import IncludeLaunchDescription +from launch.launch_description_sources import AnyLaunchDescriptionSource +from launch.logging import get_logger +import launch_testing +import pytest +from rcl_interfaces.msg import Parameter +from rcl_interfaces.msg import ParameterType +from rcl_interfaces.msg import ParameterValue +from rcl_interfaces.srv import SetParameters +import rclpy +import rclpy.qos +from tier4_planning_msgs.msg import VelocityLimit +from tier4_planning_msgs.msg import VelocityLimitClearCommand + +logger = get_logger(__name__) + + +@pytest.mark.launch_test +def generate_test_description(): + test_external_velocity_limit_selector_launch_file = os.path.join( + get_package_share_directory("autoware_external_velocity_limit_selector"), + "launch", + "external_velocity_limit_selector.launch.xml", + ) + external_velocity_limit_selector = IncludeLaunchDescription( + AnyLaunchDescriptionSource(test_external_velocity_limit_selector_launch_file), + ) + + return launch.LaunchDescription( + [ + external_velocity_limit_selector, + # Start tests right away - no need to wait for anything + launch_testing.actions.ReadyToTest(), + ] + ) + + +class TestExternalVelocityLimitSelector(unittest.TestCase): + @classmethod + def setUpClass(cls): + # Initialize the ROS context for the test node + rclpy.init() + + @classmethod + def tearDownClass(cls): + # Shutdown the ROS context + rclpy.shutdown() + + def velocity_limit_callback(self, msg): + self.msg_buffer_ = msg + + def setUp(self): + # Create a ROS node for tests + self.test_node = rclpy.create_node("test_node") + qos = rclpy.qos.QoSProfile(depth=1, durability=rclpy.qos.DurabilityPolicy.TRANSIENT_LOCAL) + self.pub_api_limit_ = self.test_node.create_publisher( + VelocityLimit, "/planning/scenario_planning/max_velocity_default", qos + ) + self.pub_internal_limit_ = self.test_node.create_publisher( + VelocityLimit, "/planning/scenario_planning/max_velocity_candidates", qos + ) + self.pub_clear_limit_ = self.test_node.create_publisher( + VelocityLimitClearCommand, "/planning/scenario_planning/clear_velocity_limit", qos + ) + self.msg_buffer_ = None + self.velocity_limit_output_ = None + self.test_node.create_subscription( + VelocityLimit, + "/planning/scenario_planning/max_velocity", + self.velocity_limit_callback, + 1, + ) + + def wait_for_output(self): + while not self.msg_buffer_: + rclpy.spin_once(self.test_node, timeout_sec=0.1) + self.velocity_limit_output_ = self.msg_buffer_ + self.msg_buffer_ = None + + def tearDown(self): + self.test_node.destroy_node() + + def update_max_vel_param(self, max_vel): + set_params_client = self.test_node.create_client( + SetParameters, "/external_velocity_limit_selector/set_parameters" + ) + while not set_params_client.wait_for_service(timeout_sec=1.0): + continue + set_params_request = SetParameters.Request() + set_params_request.parameters = [ + Parameter( + name="max_vel", + value=ParameterValue(type=ParameterType.PARAMETER_DOUBLE, double_value=max_vel), + ), + ] + future = set_params_client.call_async(set_params_request) + rclpy.spin_until_future_complete(self.test_node, future) + + if future.result() is None: + self.test_node.get_logger().error( + "Exception while calling service: %r" % future.exception() + ) + raise self.failureException("setting of initial parameters failed") + + @staticmethod + def make_velocity_limit_msg(vel): + msg = VelocityLimit() + msg.use_constraints = False + msg.max_velocity = vel + return msg + + def test_external_velocity_limit_selector_node(self): + self.update_max_vel_param(15.0) + # clear velocity limit to trigger first output + clear_cmd = VelocityLimitClearCommand(command=True) + self.pub_clear_limit_.publish(clear_cmd) + self.wait_for_output() + # velocity limit is 0 before any limit is set + self.assertEqual(self.velocity_limit_output_.max_velocity, 0.0) + + # Send velocity limits + # new API velocity limit: higher than the node param -> limit is set to the param value + api_limit = self.make_velocity_limit_msg(20.0) + self.pub_api_limit_.publish(api_limit) + self.wait_for_output() + self.assertEqual(self.velocity_limit_output_.max_velocity, 15.0) + # new API velocity limit + api_limit = self.make_velocity_limit_msg(10.0) + self.pub_api_limit_.publish(api_limit) + self.wait_for_output() + self.assertEqual(self.velocity_limit_output_.max_velocity, 10.0) + # new INTERNAL velocity limit + internal_limit = self.make_velocity_limit_msg(5.0) + self.pub_internal_limit_.publish(internal_limit) + self.wait_for_output() + self.assertEqual(self.velocity_limit_output_.max_velocity, 5.0) + # CLEAR: back to API velocity limit + self.pub_clear_limit_.publish(clear_cmd) + self.wait_for_output() + self.assertEqual(self.velocity_limit_output_.max_velocity, 10.0) + # lower the max_vel node parameter + self.update_max_vel_param(2.5) + self.pub_clear_limit_.publish(clear_cmd) + self.wait_for_output() + self.assertEqual(self.velocity_limit_output_.max_velocity, 2.5) + # velocity limit set by internal limit is no longer applied since above max_vel parameter + internal_limit = self.make_velocity_limit_msg(5.0) + self.pub_internal_limit_.publish(internal_limit) + self.wait_for_output() + self.assertEqual(self.velocity_limit_output_.max_velocity, 2.5) + + +@launch_testing.post_shutdown_test() +class TestProcessOutput(unittest.TestCase): + def test_exit_code(self, proc_info): + # Check that process exits with code 0: no error + launch_testing.asserts.assertExitCodes(proc_info) From bc409a755a2d0abce18f73c9d84aa05d851cdc5d Mon Sep 17 00:00:00 2001 From: Mitsuhiro Sakamoto <50359861+mitukou1109@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:32:12 +0900 Subject: [PATCH 16/61] feat(remaining_distance_time_calculator): integrate generate_parameter_library (#8826) * add parameter description Signed-off-by: mitukou1109 * use parameter listener Signed-off-by: mitukou1109 * supress deprecated error Signed-off-by: mitukou1109 * change scope of compile option to private Signed-off-by: mitukou1109 --------- Signed-off-by: mitukou1109 --- .../CMakeLists.txt | 12 ++++++++++++ .../package.xml | 1 + ...emaining_distance_time_calculator_parameters.yaml | 4 ++++ .../src/remaining_distance_time_calculator_node.cpp | 6 ++++-- .../src/remaining_distance_time_calculator_node.hpp | 8 ++------ 5 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 planning/autoware_remaining_distance_time_calculator/param/remaining_distance_time_calculator_parameters.yaml diff --git a/planning/autoware_remaining_distance_time_calculator/CMakeLists.txt b/planning/autoware_remaining_distance_time_calculator/CMakeLists.txt index d29a153a0ce5d..31fc4b1572f33 100644 --- a/planning/autoware_remaining_distance_time_calculator/CMakeLists.txt +++ b/planning/autoware_remaining_distance_time_calculator/CMakeLists.txt @@ -4,10 +4,22 @@ project(autoware_remaining_distance_time_calculator) find_package(autoware_cmake REQUIRED) autoware_package() +generate_parameter_library(remaining_distance_time_calculator_parameters + param/remaining_distance_time_calculator_parameters.yaml +) + ament_auto_add_library(${PROJECT_NAME} SHARED src/remaining_distance_time_calculator_node.cpp ) +target_link_libraries(${PROJECT_NAME} + remaining_distance_time_calculator_parameters +) + +target_compile_options(${PROJECT_NAME} PRIVATE + -Wno-error=deprecated-declarations +) + rclcpp_components_register_node(${PROJECT_NAME} PLUGIN "autoware::remaining_distance_time_calculator::RemainingDistanceTimeCalculatorNode" EXECUTABLE ${PROJECT_NAME}_node diff --git a/planning/autoware_remaining_distance_time_calculator/package.xml b/planning/autoware_remaining_distance_time_calculator/package.xml index 924e6d62d6aba..568f677a0c13d 100644 --- a/planning/autoware_remaining_distance_time_calculator/package.xml +++ b/planning/autoware_remaining_distance_time_calculator/package.xml @@ -18,6 +18,7 @@ autoware_route_handler autoware_test_utils autoware_universe_utils + generate_parameter_library geometry_msgs nav_msgs rclcpp diff --git a/planning/autoware_remaining_distance_time_calculator/param/remaining_distance_time_calculator_parameters.yaml b/planning/autoware_remaining_distance_time_calculator/param/remaining_distance_time_calculator_parameters.yaml new file mode 100644 index 0000000000000..0f1b1b9efbb6d --- /dev/null +++ b/planning/autoware_remaining_distance_time_calculator/param/remaining_distance_time_calculator_parameters.yaml @@ -0,0 +1,4 @@ +remaining_distance_time_calculator: + update_rate: + type: double + description: Timer callback period. [Hz] diff --git a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp index 7932a2531185f..74f3f2f43077d 100644 --- a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp +++ b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.cpp @@ -65,9 +65,11 @@ RemainingDistanceTimeCalculatorNode::RemainingDistanceTimeCalculatorNode( "~/output/mission_remaining_distance_time", rclcpp::QoS(rclcpp::KeepLast(10)).durability_volatile().reliable()); - node_param_.update_rate = declare_parameter("update_rate"); + param_listener_ = std::make_shared<::remaining_distance_time_calculator::ParamListener>( + this->get_node_parameters_interface()); + const auto param = param_listener_->get_params(); - const auto period_ns = rclcpp::Rate(node_param_.update_rate).period(); + const auto period_ns = rclcpp::Rate(param.update_rate).period(); timer_ = rclcpp::create_timer( this, get_clock(), period_ns, std::bind(&RemainingDistanceTimeCalculatorNode::on_timer, this)); } diff --git a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp index b7af8861bf524..8a38941d383ee 100644 --- a/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp +++ b/planning/autoware_remaining_distance_time_calculator/src/remaining_distance_time_calculator_node.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -39,11 +40,6 @@ namespace autoware::remaining_distance_time_calculator { -struct NodeParam -{ - double update_rate{0.0}; -}; - class RemainingDistanceTimeCalculatorNode : public rclcpp::Node { public: @@ -86,7 +82,7 @@ class RemainingDistanceTimeCalculatorNode : public rclcpp::Node double remaining_time_; // Parameter - NodeParam node_param_; + std::shared_ptr<::remaining_distance_time_calculator::ParamListener> param_listener_; // Callbacks void on_timer(); From 87d7988fae3ac1b135caa6de0c6911da8e4e154d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=83=E5=88=9A?= <90366790+liuXinGangChina@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:41:50 +0800 Subject: [PATCH 17/61] feat(autoware_localization_util): porting from universe to core, autoware_localization_util, remove from universe repo (#9888) task: porting from universe to core, autoware_localization_util, remove from universe repo : v0.0 Signed-off-by: liuXinGangChina --- .../autoware_localization_util/CHANGELOG.rst | 51 ---- .../autoware_localization_util/CMakeLists.txt | 29 -- .../autoware_localization_util/README.md | 5 - .../localization_util/covariance_ellipse.hpp | 44 --- .../localization_util/matrix_type.hpp | 26 -- .../localization_util/smart_pose_buffer.hpp | 71 ----- .../tree_structured_parzen_estimator.hpp | 87 ------ .../autoware/localization_util/util_func.hpp | 88 ------ .../autoware_localization_util/package.xml | 35 --- .../src/covariance_ellipse.cpp | 92 ------- .../src/smart_pose_buffer.cpp | 158 ----------- .../src/tree_structured_parzen_estimator.cpp | 185 ------------- .../src/util_func.cpp | 257 ------------------ .../test/test_smart_pose_buffer.cpp | 109 -------- .../test/test_tpe.cpp | 75 ----- 15 files changed, 1312 deletions(-) delete mode 100644 localization/autoware_localization_util/CHANGELOG.rst delete mode 100644 localization/autoware_localization_util/CMakeLists.txt delete mode 100644 localization/autoware_localization_util/README.md delete mode 100644 localization/autoware_localization_util/include/autoware/localization_util/covariance_ellipse.hpp delete mode 100644 localization/autoware_localization_util/include/autoware/localization_util/matrix_type.hpp delete mode 100644 localization/autoware_localization_util/include/autoware/localization_util/smart_pose_buffer.hpp delete mode 100644 localization/autoware_localization_util/include/autoware/localization_util/tree_structured_parzen_estimator.hpp delete mode 100644 localization/autoware_localization_util/include/autoware/localization_util/util_func.hpp delete mode 100644 localization/autoware_localization_util/package.xml delete mode 100644 localization/autoware_localization_util/src/covariance_ellipse.cpp delete mode 100644 localization/autoware_localization_util/src/smart_pose_buffer.cpp delete mode 100644 localization/autoware_localization_util/src/tree_structured_parzen_estimator.cpp delete mode 100644 localization/autoware_localization_util/src/util_func.cpp delete mode 100644 localization/autoware_localization_util/test/test_smart_pose_buffer.cpp delete mode 100644 localization/autoware_localization_util/test/test_tpe.cpp diff --git a/localization/autoware_localization_util/CHANGELOG.rst b/localization/autoware_localization_util/CHANGELOG.rst deleted file mode 100644 index be40e3ee8560e..0000000000000 --- a/localization/autoware_localization_util/CHANGELOG.rst +++ /dev/null @@ -1,51 +0,0 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Changelog for package autoware_localization_util -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -0.40.0 (2024-12-12) -------------------- -* Merge branch 'main' into release-0.40.0 -* Revert "chore(package.xml): bump version to 0.39.0 (`#9587 `_)" - This reverts commit c9f0f2688c57b0f657f5c1f28f036a970682e7f5. -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* chore(package.xml): bump version to 0.39.0 (`#9587 `_) - * chore(package.xml): bump version to 0.39.0 - * fix: fix ticket links in CHANGELOG.rst - * fix: remove unnecessary diff - --------- - Co-authored-by: Yutaka Kondo -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* fix(cpplint): include what you use - localization (`#9567 `_) -* 0.39.0 -* update changelog -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* Contributors: Esteve Fernandez, Fumiya Watanabe, M. Fatih Cırıt, Ryohsuke Mitsudome, Yutaka Kondo - -0.39.0 (2024-11-25) -------------------- -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* Contributors: Esteve Fernandez, Yutaka Kondo - -0.38.0 (2024-11-08) -------------------- -* unify package.xml version to 0.37.0 -* refactor(localization_util)!: prefix package and namespace with autoware (`#8922 `_) - add autoware prefix to localization_util -* Contributors: Masaki Baba, Yutaka Kondo - -0.26.0 (2024-04-03) -------------------- diff --git a/localization/autoware_localization_util/CMakeLists.txt b/localization/autoware_localization_util/CMakeLists.txt deleted file mode 100644 index de62633124f3d..0000000000000 --- a/localization/autoware_localization_util/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(autoware_localization_util) - -find_package(autoware_cmake REQUIRED) -autoware_package() - -ament_auto_add_library(${PROJECT_NAME} SHARED - src/util_func.cpp - src/smart_pose_buffer.cpp - src/tree_structured_parzen_estimator.cpp - src/covariance_ellipse.cpp -) - -if(BUILD_TESTING) - find_package(ament_cmake_gtest REQUIRED) - ament_auto_add_gtest(test_smart_pose_buffer - test/test_smart_pose_buffer.cpp - src/smart_pose_buffer.cpp - ) - - ament_auto_add_gtest(test_tpe - test/test_tpe.cpp - src/tree_structured_parzen_estimator.cpp - ) -endif() - -ament_auto_package( - INSTALL_TO_SHARE -) diff --git a/localization/autoware_localization_util/README.md b/localization/autoware_localization_util/README.md deleted file mode 100644 index f7fddd9eebf05..0000000000000 --- a/localization/autoware_localization_util/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# autoware_localization_util - -`autoware_localization_util` is a localization utility package. - -This package does not have a node, it is just a library. diff --git a/localization/autoware_localization_util/include/autoware/localization_util/covariance_ellipse.hpp b/localization/autoware_localization_util/include/autoware/localization_util/covariance_ellipse.hpp deleted file mode 100644 index abd0af46856b0..0000000000000 --- a/localization/autoware_localization_util/include/autoware/localization_util/covariance_ellipse.hpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2024 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__LOCALIZATION_UTIL__COVARIANCE_ELLIPSE_HPP_ -#define AUTOWARE__LOCALIZATION_UTIL__COVARIANCE_ELLIPSE_HPP_ - -#include - -#include -#include - -namespace autoware::localization_util -{ - -struct Ellipse -{ - double long_radius; - double short_radius; - double yaw; - Eigen::Matrix2d P; - double size_lateral_direction; -}; - -Ellipse calculate_xy_ellipse( - const geometry_msgs::msg::PoseWithCovariance & pose_with_covariance, const double scale); - -visualization_msgs::msg::Marker create_ellipse_marker( - const Ellipse & ellipse, const std_msgs::msg::Header & header, - const geometry_msgs::msg::PoseWithCovariance & pose_with_covariance); - -} // namespace autoware::localization_util - -#endif // AUTOWARE__LOCALIZATION_UTIL__COVARIANCE_ELLIPSE_HPP_ diff --git a/localization/autoware_localization_util/include/autoware/localization_util/matrix_type.hpp b/localization/autoware_localization_util/include/autoware/localization_util/matrix_type.hpp deleted file mode 100644 index bda6ff19f2867..0000000000000 --- a/localization/autoware_localization_util/include/autoware/localization_util/matrix_type.hpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2021 TierIV -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__LOCALIZATION_UTIL__MATRIX_TYPE_HPP_ -#define AUTOWARE__LOCALIZATION_UTIL__MATRIX_TYPE_HPP_ - -#include - -namespace autoware::localization_util -{ -using Matrix6d = Eigen::Matrix; -using RowMatrixXd = Eigen::Matrix; -} // namespace autoware::localization_util - -#endif // AUTOWARE__LOCALIZATION_UTIL__MATRIX_TYPE_HPP_ diff --git a/localization/autoware_localization_util/include/autoware/localization_util/smart_pose_buffer.hpp b/localization/autoware_localization_util/include/autoware/localization_util/smart_pose_buffer.hpp deleted file mode 100644 index 8c10506c36753..0000000000000 --- a/localization/autoware_localization_util/include/autoware/localization_util/smart_pose_buffer.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2015-2019 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__LOCALIZATION_UTIL__SMART_POSE_BUFFER_HPP_ -#define AUTOWARE__LOCALIZATION_UTIL__SMART_POSE_BUFFER_HPP_ - -#include "autoware/localization_util/util_func.hpp" - -#include - -#include - -#include - -namespace autoware::localization_util -{ -class SmartPoseBuffer -{ -private: - using PoseWithCovarianceStamped = geometry_msgs::msg::PoseWithCovarianceStamped; - -public: - struct InterpolateResult - { - PoseWithCovarianceStamped old_pose; - PoseWithCovarianceStamped new_pose; - PoseWithCovarianceStamped interpolated_pose; - }; - - SmartPoseBuffer() = delete; - SmartPoseBuffer( - const rclcpp::Logger & logger, const double & pose_timeout_sec, - const double & pose_distance_tolerance_meters); - - std::optional interpolate(const rclcpp::Time & target_ros_time); - - void push_back(const PoseWithCovarianceStamped::ConstSharedPtr & pose_msg_ptr); - - void pop_old(const rclcpp::Time & target_ros_time); - - void clear(); - -private: - rclcpp::Logger logger_; - std::deque pose_buffer_; - std::mutex mutex_; // This mutex is for pose_buffer_ - - const double pose_timeout_sec_; - const double pose_distance_tolerance_meters_; - - [[nodiscard]] bool validate_time_stamp_difference( - const rclcpp::Time & target_time, const rclcpp::Time & reference_time, - const double time_tolerance_sec) const; - [[nodiscard]] bool validate_position_difference( - const geometry_msgs::msg::Point & target_point, - const geometry_msgs::msg::Point & reference_point, const double distance_tolerance_m_) const; -}; -} // namespace autoware::localization_util - -#endif // AUTOWARE__LOCALIZATION_UTIL__SMART_POSE_BUFFER_HPP_ diff --git a/localization/autoware_localization_util/include/autoware/localization_util/tree_structured_parzen_estimator.hpp b/localization/autoware_localization_util/include/autoware/localization_util/tree_structured_parzen_estimator.hpp deleted file mode 100644 index ddf7625c202ec..0000000000000 --- a/localization/autoware_localization_util/include/autoware/localization_util/tree_structured_parzen_estimator.hpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2023 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__LOCALIZATION_UTIL__TREE_STRUCTURED_PARZEN_ESTIMATOR_HPP_ -#define AUTOWARE__LOCALIZATION_UTIL__TREE_STRUCTURED_PARZEN_ESTIMATOR_HPP_ - -/* -A implementation of tree-structured parzen estimator (TPE) -See below pdf for the TPE algorithm detail. -https://papers.nips.cc/paper_files/paper/2011/file/86e8f7ab32cfd12577bc2619bc635690-Paper.pdf - -Optuna is also used as a reference for implementation. -https://github.com/optuna/optuna -*/ - -#include -#include -#include - -namespace autoware::localization_util -{ -class TreeStructuredParzenEstimator -{ -public: - using Input = std::vector; - using Score = double; - struct Trial - { - Input input; - Score score; - }; - - enum Direction { - MINIMIZE = 0, - MAXIMIZE = 1, - }; - - enum Index { - TRANS_X = 0, - TRANS_Y = 1, - TRANS_Z = 2, - ANGLE_X = 3, - ANGLE_Y = 4, - ANGLE_Z = 5, - INDEX_NUM = 6, - }; - - TreeStructuredParzenEstimator() = delete; - TreeStructuredParzenEstimator( - const Direction direction, const int64_t n_startup_trials, std::vector sample_mean, - std::vector sample_stddev); - void add_trial(const Trial & trial); - [[nodiscard]] Input get_next_input() const; - -private: - static constexpr double max_good_rate = 0.10; - static constexpr int64_t n_ei_candidates = 100; - - static std::mt19937_64 engine; - - [[nodiscard]] double compute_log_likelihood_ratio(const Input & input) const; - [[nodiscard]] static double log_gaussian_pdf( - const Input & input, const Input & mu, const Input & sigma); - - std::vector trials_; - int64_t above_num_; - const Direction direction_; - const int64_t n_startup_trials_; - const int64_t input_dimension_; - const std::vector sample_mean_; - const std::vector sample_stddev_; - Input base_stddev_; -}; -} // namespace autoware::localization_util - -#endif // AUTOWARE__LOCALIZATION_UTIL__TREE_STRUCTURED_PARZEN_ESTIMATOR_HPP_ diff --git a/localization/autoware_localization_util/include/autoware/localization_util/util_func.hpp b/localization/autoware_localization_util/include/autoware/localization_util/util_func.hpp deleted file mode 100644 index bef9968f34b6f..0000000000000 --- a/localization/autoware_localization_util/include/autoware/localization_util/util_func.hpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015-2019 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__LOCALIZATION_UTIL__UTIL_FUNC_HPP_ -#define AUTOWARE__LOCALIZATION_UTIL__UTIL_FUNC_HPP_ - -#include -#include -#include -#include - -#ifdef ROS_DISTRO_GALACTIC -#include -#include -#else -#include - -#include -#endif - -#include -#include -#include -#include -#include -#include - -namespace autoware::localization_util -{ -// ref by http://takacity.blog.fc2.com/blog-entry-69.html -std_msgs::msg::ColorRGBA exchange_color_crc(double x); - -double calc_diff_for_radian(const double lhs_rad, const double rhs_rad); - -// x: roll, y: pitch, z: yaw -geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::Pose & pose); -geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::PoseStamped & pose); -geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::PoseWithCovarianceStamped & pose); - -geometry_msgs::msg::Quaternion rpy_rad_to_quaternion( - const double r_rad, const double p_rad, const double y_rad); -geometry_msgs::msg::Quaternion rpy_deg_to_quaternion( - const double r_deg, const double p_deg, const double y_deg); - -geometry_msgs::msg::Twist calc_twist( - const geometry_msgs::msg::PoseStamped & pose_a, const geometry_msgs::msg::PoseStamped & pose_b); - -geometry_msgs::msg::PoseStamped interpolate_pose( - const geometry_msgs::msg::PoseStamped & pose_a, const geometry_msgs::msg::PoseStamped & pose_b, - const rclcpp::Time & time_stamp); - -geometry_msgs::msg::PoseStamped interpolate_pose( - const geometry_msgs::msg::PoseWithCovarianceStamped & pose_a, - const geometry_msgs::msg::PoseWithCovarianceStamped & pose_b, const rclcpp::Time & time_stamp); - -Eigen::Affine3d pose_to_affine3d(const geometry_msgs::msg::Pose & ros_pose); -Eigen::Matrix4f pose_to_matrix4f(const geometry_msgs::msg::Pose & ros_pose); -geometry_msgs::msg::Pose matrix4f_to_pose(const Eigen::Matrix4f & eigen_pose_matrix); -Eigen::Vector3d point_to_vector3d(const geometry_msgs::msg::Point & ros_pos); - -template -T transform(const T & input, const geometry_msgs::msg::TransformStamped & transform) -{ - T output; - tf2::doTransform(input, output, transform); - return output; -} - -double norm(const geometry_msgs::msg::Point & p1, const geometry_msgs::msg::Point & p2); - -void output_pose_with_cov_to_log( - const rclcpp::Logger & logger, const std::string & prefix, - const geometry_msgs::msg::PoseWithCovarianceStamped & pose_with_cov); - -} // namespace autoware::localization_util - -#endif // AUTOWARE__LOCALIZATION_UTIL__UTIL_FUNC_HPP_ diff --git a/localization/autoware_localization_util/package.xml b/localization/autoware_localization_util/package.xml deleted file mode 100644 index 89ad7c24840dd..0000000000000 --- a/localization/autoware_localization_util/package.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - autoware_localization_util - 0.40.0 - The autoware_localization_util package - Yamato Ando - Masahiro Sakamoto - Shintaro Sakoda - Kento Yabuuchi - NGUYEN Viet Anh - Taiki Yamada - Ryu Yamamoto - Apache License 2.0 - Yamato Ando - - ament_cmake_auto - autoware_cmake - - diagnostic_msgs - geometry_msgs - rclcpp - std_msgs - tf2 - tf2_eigen - tf2_geometry_msgs - visualization_msgs - - ament_cmake_cppcheck - ament_lint_auto - - - ament_cmake - - diff --git a/localization/autoware_localization_util/src/covariance_ellipse.cpp b/localization/autoware_localization_util/src/covariance_ellipse.cpp deleted file mode 100644 index 847f89e0da9b3..0000000000000 --- a/localization/autoware_localization_util/src/covariance_ellipse.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2024 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/localization_util/covariance_ellipse.hpp" - -#include - -#include -#ifdef ROS_DISTRO_GALACTIC -#include -#else -#include -#endif - -namespace autoware::localization_util -{ - -Ellipse calculate_xy_ellipse( - const geometry_msgs::msg::PoseWithCovariance & pose_with_covariance, const double scale) -{ - // input geometry_msgs::PoseWithCovariance contain 6x6 matrix - Eigen::Matrix2d xy_covariance; - const auto cov = pose_with_covariance.covariance; - xy_covariance(0, 0) = cov[0 * 6 + 0]; - xy_covariance(0, 1) = cov[0 * 6 + 1]; - xy_covariance(1, 0) = cov[1 * 6 + 0]; - xy_covariance(1, 1) = cov[1 * 6 + 1]; - - Eigen::SelfAdjointEigenSolver eigensolver(xy_covariance); - - Ellipse ellipse; - - // eigen values and vectors are sorted in ascending order - ellipse.long_radius = scale * std::sqrt(eigensolver.eigenvalues()(1)); - ellipse.short_radius = scale * std::sqrt(eigensolver.eigenvalues()(0)); - - // principal component vector - const Eigen::Vector2d pc_vector = eigensolver.eigenvectors().col(1); - ellipse.yaw = std::atan2(pc_vector.y(), pc_vector.x()); - - // ellipse size along lateral direction (body-frame) - ellipse.P = xy_covariance; - const double yaw_vehicle = tf2::getYaw(pose_with_covariance.pose.orientation); - const Eigen::Matrix2d & p_inv = ellipse.P.inverse(); - Eigen::MatrixXd e(2, 1); - e(0, 0) = std::cos(yaw_vehicle); - e(1, 0) = std::sin(yaw_vehicle); - const double d = std::sqrt((e.transpose() * p_inv * e)(0, 0) / p_inv.determinant()); - ellipse.size_lateral_direction = scale * d; - - return ellipse; -} - -visualization_msgs::msg::Marker create_ellipse_marker( - const Ellipse & ellipse, const std_msgs::msg::Header & header, - const geometry_msgs::msg::PoseWithCovariance & pose_with_covariance) -{ - tf2::Quaternion quat; - quat.setEuler(0, 0, ellipse.yaw); - - const double ellipse_long_radius = std::min(ellipse.long_radius, 30.0); - const double ellipse_short_radius = std::min(ellipse.short_radius, 30.0); - visualization_msgs::msg::Marker marker; - marker.header = header; - marker.ns = "error_ellipse"; - marker.id = 0; - marker.type = visualization_msgs::msg::Marker::SPHERE; - marker.action = visualization_msgs::msg::Marker::ADD; - marker.pose = pose_with_covariance.pose; - marker.pose.orientation = tf2::toMsg(quat); - marker.scale.x = ellipse_long_radius * 2; - marker.scale.y = ellipse_short_radius * 2; - marker.scale.z = 0.01; - marker.color.a = 0.1; - marker.color.r = 0.0; - marker.color.g = 0.0; - marker.color.b = 1.0; - return marker; -} - -} // namespace autoware::localization_util diff --git a/localization/autoware_localization_util/src/smart_pose_buffer.cpp b/localization/autoware_localization_util/src/smart_pose_buffer.cpp deleted file mode 100644 index 3b529d68cf6c5..0000000000000 --- a/localization/autoware_localization_util/src/smart_pose_buffer.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2023- Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/localization_util/smart_pose_buffer.hpp" - -namespace autoware::localization_util -{ -SmartPoseBuffer::SmartPoseBuffer( - const rclcpp::Logger & logger, const double & pose_timeout_sec, - const double & pose_distance_tolerance_meters) -: logger_(logger), - pose_timeout_sec_(pose_timeout_sec), - pose_distance_tolerance_meters_(pose_distance_tolerance_meters) -{ -} - -std::optional SmartPoseBuffer::interpolate( - const rclcpp::Time & target_ros_time) -{ - InterpolateResult result; - - { - std::lock_guard lock(mutex_); - - if (pose_buffer_.size() < 2) { - RCLCPP_INFO(logger_, "pose_buffer_.size() < 2"); - return std::nullopt; - } - - const rclcpp::Time time_first = pose_buffer_.front()->header.stamp; - const rclcpp::Time time_last = pose_buffer_.back()->header.stamp; - - if (target_ros_time < time_first) { - RCLCPP_INFO(logger_, "Mismatch between pose timestamp and current timestamp"); - return std::nullopt; - } - - // [time_last < target_ros_time] is acceptable here. - // It is possible that the target_ros_time (often sensor timestamp) is newer than the latest - // timestamp of buffered pose (often EKF). - // However, if the timestamp difference is too large, - // it will later be rejected by validate_time_stamp_difference. - - // get the nearest poses - result.old_pose = *pose_buffer_.front(); - for (const PoseWithCovarianceStamped::ConstSharedPtr & pose_cov_msg_ptr : pose_buffer_) { - result.new_pose = *pose_cov_msg_ptr; - const rclcpp::Time pose_time_stamp = result.new_pose.header.stamp; - if (pose_time_stamp > target_ros_time) { - break; - } - result.old_pose = *pose_cov_msg_ptr; - } - } - - // check the time stamp - const bool is_old_pose_valid = validate_time_stamp_difference( - result.old_pose.header.stamp, target_ros_time, pose_timeout_sec_); - const bool is_new_pose_valid = validate_time_stamp_difference( - result.new_pose.header.stamp, target_ros_time, pose_timeout_sec_); - - // check the position jumping (ex. immediately after the initial pose estimation) - const bool is_pose_diff_valid = validate_position_difference( - result.old_pose.pose.pose.position, result.new_pose.pose.pose.position, - pose_distance_tolerance_meters_); - - // all validations must be true - if (!(is_old_pose_valid && is_new_pose_valid && is_pose_diff_valid)) { - return std::nullopt; - } - - // interpolate the pose - const geometry_msgs::msg::PoseStamped interpolated_pose_msg = - interpolate_pose(result.old_pose, result.new_pose, target_ros_time); - result.interpolated_pose.header = interpolated_pose_msg.header; - result.interpolated_pose.pose.pose = interpolated_pose_msg.pose; - // This does not interpolate the covariance. - // interpolated_pose.pose.covariance is always set to old_pose.covariance - result.interpolated_pose.pose.covariance = result.old_pose.pose.covariance; - return result; -} - -void SmartPoseBuffer::push_back(const PoseWithCovarianceStamped::ConstSharedPtr & pose_msg_ptr) -{ - std::lock_guard lock(mutex_); - if (!pose_buffer_.empty()) { - // Check for non-chronological timestamp order - // This situation can arise when replaying a rosbag multiple times - const rclcpp::Time end_time = pose_buffer_.back()->header.stamp; - const rclcpp::Time msg_time = pose_msg_ptr->header.stamp; - if (msg_time < end_time) { - // Clear the buffer if timestamps are reversed to maintain chronological order - pose_buffer_.clear(); - } - } - pose_buffer_.push_back(pose_msg_ptr); -} - -void SmartPoseBuffer::pop_old(const rclcpp::Time & target_ros_time) -{ - std::lock_guard lock(mutex_); - while (!pose_buffer_.empty()) { - if (rclcpp::Time(pose_buffer_.front()->header.stamp) >= target_ros_time) { - break; - } - pose_buffer_.pop_front(); - } -} - -void SmartPoseBuffer::clear() -{ - std::lock_guard lock(mutex_); - pose_buffer_.clear(); -} - -bool SmartPoseBuffer::validate_time_stamp_difference( - const rclcpp::Time & target_time, const rclcpp::Time & reference_time, - const double time_tolerance_sec) const -{ - const double dt = std::abs((target_time - reference_time).seconds()); - const bool success = dt < time_tolerance_sec; - if (!success) { - RCLCPP_WARN( - logger_, - "Validation error. The reference time is %lf[sec], but the target time is %lf[sec]. The " - "difference is %lf[sec] (the tolerance is %lf[sec]).", - reference_time.seconds(), target_time.seconds(), dt, time_tolerance_sec); - } - return success; -} - -bool SmartPoseBuffer::validate_position_difference( - const geometry_msgs::msg::Point & target_point, const geometry_msgs::msg::Point & reference_point, - const double distance_tolerance_m_) const -{ - const double distance = norm(target_point, reference_point); - const bool success = distance < distance_tolerance_m_; - if (!success) { - RCLCPP_WARN( - logger_, - "Validation error. The distance from reference position to target position is %lf[m] (the " - "tolerance is %lf[m]).", - distance, distance_tolerance_m_); - } - return success; -} -} // namespace autoware::localization_util diff --git a/localization/autoware_localization_util/src/tree_structured_parzen_estimator.cpp b/localization/autoware_localization_util/src/tree_structured_parzen_estimator.cpp deleted file mode 100644 index e9f0318d1e06d..0000000000000 --- a/localization/autoware_localization_util/src/tree_structured_parzen_estimator.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2023 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/localization_util/tree_structured_parzen_estimator.hpp" - -#include -#include -#include -#include -#include -#include -#include - -namespace autoware::localization_util -{ -// random number generator -std::mt19937_64 TreeStructuredParzenEstimator::engine(0); - -TreeStructuredParzenEstimator::TreeStructuredParzenEstimator( - const Direction direction, const int64_t n_startup_trials, std::vector sample_mean, - std::vector sample_stddev) -: above_num_(0), - direction_(direction), - n_startup_trials_(n_startup_trials), - input_dimension_(INDEX_NUM), - sample_mean_(std::move(sample_mean)), - sample_stddev_(std::move(sample_stddev)) -{ - if (sample_mean_.size() != ANGLE_Z) { - std::cerr << "sample_mean size is invalid" << std::endl; - throw std::runtime_error("sample_mean size is invalid"); - } - if (sample_stddev_.size() != ANGLE_Z) { - std::cerr << "sample_stddev size is invalid" << std::endl; - throw std::runtime_error("sample_stddev size is invalid"); - } - // base_stddev_ is defined as the stable convergence range of ndt_scan_matcher. - base_stddev_.resize(input_dimension_); - base_stddev_[TRANS_X] = 0.25; // [m] - base_stddev_[TRANS_Y] = 0.25; // [m] - base_stddev_[TRANS_Z] = 0.25; // [m] - base_stddev_[ANGLE_X] = 1.0 / 180.0 * M_PI; // [rad] - base_stddev_[ANGLE_Y] = 1.0 / 180.0 * M_PI; // [rad] - base_stddev_[ANGLE_Z] = 2.5 / 180.0 * M_PI; // [rad] -} - -void TreeStructuredParzenEstimator::add_trial(const Trial & trial) -{ - trials_.push_back(trial); - std::sort(trials_.begin(), trials_.end(), [this](const Trial & lhs, const Trial & rhs) { - return (direction_ == Direction::MAXIMIZE ? lhs.score > rhs.score : lhs.score < rhs.score); - }); - above_num_ = std::min( - {static_cast(10), - static_cast(static_cast(trials_.size()) * max_good_rate)}); -} - -TreeStructuredParzenEstimator::Input TreeStructuredParzenEstimator::get_next_input() const -{ - std::normal_distribution dist_normal_trans_x( - sample_mean_[TRANS_X], sample_stddev_[TRANS_X]); - std::normal_distribution dist_normal_trans_y( - sample_mean_[TRANS_Y], sample_stddev_[TRANS_Y]); - std::normal_distribution dist_normal_trans_z( - sample_mean_[TRANS_Z], sample_stddev_[TRANS_Z]); - std::normal_distribution dist_normal_angle_x( - sample_mean_[ANGLE_X], sample_stddev_[ANGLE_X]); - std::normal_distribution dist_normal_angle_y( - sample_mean_[ANGLE_Y], sample_stddev_[ANGLE_Y]); - std::uniform_real_distribution dist_uniform_angle_z(-M_PI, M_PI); - - if (static_cast(trials_.size()) < n_startup_trials_ || above_num_ == 0) { - // Random sampling based on prior until the number of trials reaches `n_startup_trials_`. - Input input(input_dimension_); - input[TRANS_X] = dist_normal_trans_x(engine); - input[TRANS_Y] = dist_normal_trans_y(engine); - input[TRANS_Z] = dist_normal_trans_z(engine); - input[ANGLE_X] = dist_normal_angle_x(engine); - input[ANGLE_Y] = dist_normal_angle_y(engine); - input[ANGLE_Z] = dist_uniform_angle_z(engine); - return input; - } - - Input best_input; - double best_log_likelihood_ratio = std::numeric_limits::lowest(); - for (int64_t i = 0; i < n_ei_candidates; i++) { - Input input(input_dimension_); - input[TRANS_X] = dist_normal_trans_x(engine); - input[TRANS_Y] = dist_normal_trans_y(engine); - input[TRANS_Z] = dist_normal_trans_z(engine); - input[ANGLE_X] = dist_normal_angle_x(engine); - input[ANGLE_Y] = dist_normal_angle_y(engine); - input[ANGLE_Z] = dist_uniform_angle_z(engine); - const double log_likelihood_ratio = compute_log_likelihood_ratio(input); - if (log_likelihood_ratio > best_log_likelihood_ratio) { - best_log_likelihood_ratio = log_likelihood_ratio; - best_input = input; - } - } - return best_input; -} - -double TreeStructuredParzenEstimator::compute_log_likelihood_ratio(const Input & input) const -{ - const auto n = static_cast(trials_.size()); - - // The above KDE and the below KDE are calculated respectively, and the ratio is the criteria to - // select best sample. - std::vector above_logs; - std::vector below_logs; - - for (int64_t i = 0; i < n; i++) { - const double log_p = log_gaussian_pdf(input, trials_[i].input, base_stddev_); - if (i < above_num_) { - const double w = 1.0 / static_cast(above_num_); - const double log_w = std::log(w); - above_logs.push_back(log_p + log_w); - } else { - const double w = 1.0 / static_cast(n - above_num_); - const double log_w = std::log(w); - below_logs.push_back(log_p + log_w); - } - } - - auto log_sum_exp = [](const std::vector & log_vec) { - const double max = *std::max_element(log_vec.begin(), log_vec.end()); - double sum = std::accumulate( - log_vec.begin(), log_vec.end(), 0.0, - [max](double total, double log_v) { return total + std::exp(log_v - max); }); - return max + std::log(sum); - }; - - const double above = log_sum_exp(above_logs); - const double below = log_sum_exp(below_logs); - - // Multiply by a constant so that the score near the "below sample" becomes lower. - // cspell:disable-line TODO(Shintaro Sakoda): It's theoretically incorrect, consider it again - // later. - const double r = above - below * 5.0; - return r; -} - -double TreeStructuredParzenEstimator::log_gaussian_pdf( - const Input & input, const Input & mu, const Input & sigma) -{ - const double log_2pi = std::log(2.0 * M_PI); - auto log_gaussian_pdf_1d = [&](const double diff, const double sigma) { - return -0.5 * log_2pi - std::log(sigma) - (diff * diff) / (2.0 * sigma * sigma); - }; - - const auto n = static_cast(input.size()); - - double result = 0.0; - for (int64_t i = 0; i < n; i++) { - double diff = input[i] - mu[i]; - if (i == ANGLE_Z) { - // Normalize the loop variable to [-pi, pi) - while (diff >= M_PI) { - diff -= 2 * M_PI; - } - while (diff < -M_PI) { - diff += 2 * M_PI; - } - } - // Experimentally, it is better to consider only trans_xy and yaw, so ignore trans_z, angle_x, - // angle_y. - if (i == TRANS_Z || i == ANGLE_X || i == ANGLE_Y) { - continue; - } - result += log_gaussian_pdf_1d(diff, sigma[i]); - } - return result; -} -} // namespace autoware::localization_util diff --git a/localization/autoware_localization_util/src/util_func.cpp b/localization/autoware_localization_util/src/util_func.cpp deleted file mode 100644 index 17187a8d732f0..0000000000000 --- a/localization/autoware_localization_util/src/util_func.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2015-2019 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/localization_util/util_func.hpp" - -#include "autoware/localization_util/matrix_type.hpp" - -#include -#include - -namespace autoware::localization_util -{ -// ref by http://takacity.blog.fc2.com/blog-entry-69.html -std_msgs::msg::ColorRGBA exchange_color_crc(double x) -{ - std_msgs::msg::ColorRGBA color; - - x = std::max(x, 0.0); - x = std::min(x, 0.9999); - - if (x <= 0.25) { - color.b = 1.0; - color.g = static_cast(std::sin(x * 2.0 * M_PI)); - color.r = 0; - } else if (x <= 0.5) { - color.b = static_cast(std::sin(x * 2 * M_PI)); - color.g = 1.0; - color.r = 0; - } else if (x <= 0.75) { - color.b = 0; - color.g = 1.0; - color.r = static_cast(-std::sin(x * 2.0 * M_PI)); - } else { - color.b = 0; - color.g = static_cast(-std::sin(x * 2.0 * M_PI)); - color.r = 1.0; - } - color.a = 0.999; - return color; -} - -double calc_diff_for_radian(const double lhs_rad, const double rhs_rad) -{ - double diff_rad = lhs_rad - rhs_rad; - if (diff_rad > M_PI) { - diff_rad = diff_rad - 2 * M_PI; - } else if (diff_rad < -M_PI) { - diff_rad = diff_rad + 2 * M_PI; - } - return diff_rad; -} - -Eigen::Map make_eigen_covariance(const std::array & covariance) -{ - return {covariance.data(), 6, 6}; -} - -// x: roll, y: pitch, z: yaw -geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::Pose & pose) -{ - geometry_msgs::msg::Vector3 rpy; - tf2::Quaternion q(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w); - tf2::Matrix3x3(q).getRPY(rpy.x, rpy.y, rpy.z); - return rpy; -} - -geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::PoseStamped & pose) -{ - return get_rpy(pose.pose); -} - -geometry_msgs::msg::Vector3 get_rpy(const geometry_msgs::msg::PoseWithCovarianceStamped & pose) -{ - return get_rpy(pose.pose.pose); -} - -geometry_msgs::msg::Quaternion rpy_rad_to_quaternion( - const double r_rad, const double p_rad, const double y_rad) -{ - tf2::Quaternion q; - q.setRPY(r_rad, p_rad, y_rad); - geometry_msgs::msg::Quaternion quaternion_msg; - quaternion_msg.x = q.x(); - quaternion_msg.y = q.y(); - quaternion_msg.z = q.z(); - quaternion_msg.w = q.w(); - return quaternion_msg; -} - -geometry_msgs::msg::Quaternion rpy_deg_to_quaternion( - const double r_deg, const double p_deg, const double y_deg) -{ - const double r_rad = r_deg * M_PI / 180.0; - const double p_rad = p_deg * M_PI / 180.0; - const double y_rad = y_deg * M_PI / 180.0; - return rpy_rad_to_quaternion(r_rad, p_rad, y_rad); -} - -geometry_msgs::msg::Twist calc_twist( - const geometry_msgs::msg::PoseStamped & pose_a, const geometry_msgs::msg::PoseStamped & pose_b) -{ - const rclcpp::Duration dt = rclcpp::Time(pose_b.header.stamp) - rclcpp::Time(pose_a.header.stamp); - const double dt_s = dt.seconds(); - - if (dt_s == 0) { - return geometry_msgs::msg::Twist(); - } - - const auto pose_a_rpy = get_rpy(pose_a); - const auto pose_b_rpy = get_rpy(pose_b); - - geometry_msgs::msg::Vector3 diff_xyz; - geometry_msgs::msg::Vector3 diff_rpy; - - diff_xyz.x = pose_b.pose.position.x - pose_a.pose.position.x; - diff_xyz.y = pose_b.pose.position.y - pose_a.pose.position.y; - diff_xyz.z = pose_b.pose.position.z - pose_a.pose.position.z; - diff_rpy.x = calc_diff_for_radian(pose_b_rpy.x, pose_a_rpy.x); - diff_rpy.y = calc_diff_for_radian(pose_b_rpy.y, pose_a_rpy.y); - diff_rpy.z = calc_diff_for_radian(pose_b_rpy.z, pose_a_rpy.z); - - geometry_msgs::msg::Twist twist; - twist.linear.x = diff_xyz.x / dt_s; - twist.linear.y = diff_xyz.y / dt_s; - twist.linear.z = diff_xyz.z / dt_s; - twist.angular.x = diff_rpy.x / dt_s; - twist.angular.y = diff_rpy.y / dt_s; - twist.angular.z = diff_rpy.z / dt_s; - - return twist; -} - -geometry_msgs::msg::PoseStamped interpolate_pose( - const geometry_msgs::msg::PoseStamped & pose_a, const geometry_msgs::msg::PoseStamped & pose_b, - const rclcpp::Time & time_stamp) -{ - const rclcpp::Time pose_a_time_stamp = pose_a.header.stamp; - const rclcpp::Time pose_b_time_stamp = pose_b.header.stamp; - if ( - (pose_a_time_stamp.seconds() == 0.0) || (pose_b_time_stamp.seconds() == 0.0) || - (time_stamp.seconds() == 0.0)) { - return geometry_msgs::msg::PoseStamped(); - } - - const auto twist = calc_twist(pose_a, pose_b); - const double dt = (time_stamp - pose_a_time_stamp).seconds(); - - const auto pose_a_rpy = get_rpy(pose_a); - - geometry_msgs::msg::Vector3 xyz; - geometry_msgs::msg::Vector3 rpy; - xyz.x = pose_a.pose.position.x + twist.linear.x * dt; - xyz.y = pose_a.pose.position.y + twist.linear.y * dt; - xyz.z = pose_a.pose.position.z + twist.linear.z * dt; - rpy.x = pose_a_rpy.x + twist.angular.x * dt; - rpy.y = pose_a_rpy.y + twist.angular.y * dt; - rpy.z = pose_a_rpy.z + twist.angular.z * dt; - - tf2::Quaternion tf_quaternion; - tf_quaternion.setRPY(rpy.x, rpy.y, rpy.z); - - geometry_msgs::msg::PoseStamped pose; - pose.header = pose_a.header; - pose.header.stamp = time_stamp; - pose.pose.position.x = xyz.x; - pose.pose.position.y = xyz.y; - pose.pose.position.z = xyz.z; - pose.pose.orientation = tf2::toMsg(tf_quaternion); - return pose; -} - -geometry_msgs::msg::PoseStamped interpolate_pose( - const geometry_msgs::msg::PoseWithCovarianceStamped & pose_a, - const geometry_msgs::msg::PoseWithCovarianceStamped & pose_b, const rclcpp::Time & time_stamp) -{ - geometry_msgs::msg::PoseStamped tmp_pose_a; - tmp_pose_a.header = pose_a.header; - tmp_pose_a.pose = pose_a.pose.pose; - - geometry_msgs::msg::PoseStamped tmp_pose_b; - tmp_pose_b.header = pose_b.header; - tmp_pose_b.pose = pose_b.pose.pose; - - return interpolate_pose(tmp_pose_a, tmp_pose_b, time_stamp); -} - -Eigen::Affine3d pose_to_affine3d(const geometry_msgs::msg::Pose & ros_pose) -{ - Eigen::Affine3d eigen_pose; - tf2::fromMsg(ros_pose, eigen_pose); - return eigen_pose; -} - -Eigen::Matrix4f pose_to_matrix4f(const geometry_msgs::msg::Pose & ros_pose) -{ - Eigen::Affine3d eigen_pose_affine = pose_to_affine3d(ros_pose); - Eigen::Matrix4f eigen_pose_matrix = eigen_pose_affine.matrix().cast(); - return eigen_pose_matrix; -} - -Eigen::Vector3d point_to_vector3d(const geometry_msgs::msg::Point & ros_pos) -{ - Eigen::Vector3d eigen_pos; - eigen_pos.x() = ros_pos.x; - eigen_pos.y() = ros_pos.y; - eigen_pos.z() = ros_pos.z; - return eigen_pos; -} - -geometry_msgs::msg::Pose matrix4f_to_pose(const Eigen::Matrix4f & eigen_pose_matrix) -{ - Eigen::Affine3d eigen_pose_affine; - eigen_pose_affine.matrix() = eigen_pose_matrix.cast(); - geometry_msgs::msg::Pose ros_pose = tf2::toMsg(eigen_pose_affine); - return ros_pose; -} - -double norm(const geometry_msgs::msg::Point & p1, const geometry_msgs::msg::Point & p2) -{ - const double dx = p1.x - p2.x; - const double dy = p1.y - p2.y; - const double dz = p1.z - p2.z; - return std::sqrt(dx * dx + dy * dy + dz * dz); -} - -void output_pose_with_cov_to_log( - const rclcpp::Logger & logger, const std::string & prefix, - const geometry_msgs::msg::PoseWithCovarianceStamped & pose_with_cov) -{ - const Eigen::Map covariance = - make_eigen_covariance(pose_with_cov.pose.covariance); - const geometry_msgs::msg::Pose pose = pose_with_cov.pose.pose; - geometry_msgs::msg::Vector3 rpy = get_rpy(pose); - rpy.x = rpy.x * 180.0 / M_PI; - rpy.y = rpy.y * 180.0 / M_PI; - rpy.z = rpy.z * 180.0 / M_PI; - - RCLCPP_DEBUG_STREAM( - logger, std::fixed << prefix << "," << pose.position.x << "," << pose.position.y << "," - << pose.position.z << "," << pose.orientation.x << "," << pose.orientation.y - << "," << pose.orientation.z << "," << pose.orientation.w << "," << rpy.x - << "," << rpy.y << "," << rpy.z << "," << covariance(0, 0) << "," - << covariance(1, 1) << "," << covariance(2, 2) << "," << covariance(3, 3) - << "," << covariance(4, 4) << "," << covariance(5, 5)); -} -} // namespace autoware::localization_util diff --git a/localization/autoware_localization_util/test/test_smart_pose_buffer.cpp b/localization/autoware_localization_util/test/test_smart_pose_buffer.cpp deleted file mode 100644 index d55555682be84..0000000000000 --- a/localization/autoware_localization_util/test/test_smart_pose_buffer.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2023- Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/localization_util/smart_pose_buffer.hpp" -#include "autoware/localization_util/util_func.hpp" - -#include -#include - -#include -#include - -#include -#include -#include - -using PoseWithCovarianceStamped = geometry_msgs::msg::PoseWithCovarianceStamped; -using SmartPoseBuffer = autoware::localization_util::SmartPoseBuffer; - -bool compare_pose( - const PoseWithCovarianceStamped & pose_a, const PoseWithCovarianceStamped & pose_b) -{ - return pose_a.header.stamp == pose_b.header.stamp && - pose_a.header.frame_id == pose_b.header.frame_id && - pose_a.pose.covariance == pose_b.pose.covariance && - pose_a.pose.pose.position.x == pose_b.pose.pose.position.x && - pose_a.pose.pose.position.y == pose_b.pose.pose.position.y && - pose_a.pose.pose.position.z == pose_b.pose.pose.position.z && - pose_a.pose.pose.orientation.x == pose_b.pose.pose.orientation.x && - pose_a.pose.pose.orientation.y == pose_b.pose.pose.orientation.y && - pose_a.pose.pose.orientation.z == pose_b.pose.pose.orientation.z && - pose_a.pose.pose.orientation.w == pose_b.pose.pose.orientation.w; -} - -TEST(TestSmartPoseBuffer, interpolate_pose) // NOLINT -{ - rclcpp::Logger logger = rclcpp::get_logger("test_logger"); - const double pose_timeout_sec = 10.0; - const double pose_distance_tolerance_meters = 100.0; - SmartPoseBuffer smart_pose_buffer(logger, pose_timeout_sec, pose_distance_tolerance_meters); - - // first data - PoseWithCovarianceStamped::SharedPtr old_pose_ptr = std::make_shared(); - old_pose_ptr->header.stamp.sec = 10; - old_pose_ptr->header.stamp.nanosec = 0; - old_pose_ptr->pose.pose.position.x = 10.0; - old_pose_ptr->pose.pose.position.y = 20.0; - old_pose_ptr->pose.pose.position.z = 0.0; - old_pose_ptr->pose.pose.orientation = - autoware::localization_util::rpy_deg_to_quaternion(0.0, 0.0, 0.0); - smart_pose_buffer.push_back(old_pose_ptr); - - // second data - PoseWithCovarianceStamped::SharedPtr new_pose_ptr = std::make_shared(); - new_pose_ptr->header.stamp.sec = 20; - new_pose_ptr->header.stamp.nanosec = 0; - new_pose_ptr->pose.pose.position.x = 20.0; - new_pose_ptr->pose.pose.position.y = 40.0; - new_pose_ptr->pose.pose.position.z = 0.0; - new_pose_ptr->pose.pose.orientation = - autoware::localization_util::rpy_deg_to_quaternion(0.0, 0.0, 90.0); - smart_pose_buffer.push_back(new_pose_ptr); - - // interpolate - builtin_interfaces::msg::Time target_ros_time_msg; - target_ros_time_msg.sec = 15; - target_ros_time_msg.nanosec = 0; - const std::optional & interpolate_result = - smart_pose_buffer.interpolate(target_ros_time_msg); - ASSERT_TRUE(interpolate_result.has_value()); - const SmartPoseBuffer::InterpolateResult result = interpolate_result.value(); - - // check old - EXPECT_TRUE(compare_pose(result.old_pose, *old_pose_ptr)); - - // check new - EXPECT_TRUE(compare_pose(result.new_pose, *new_pose_ptr)); - - // check interpolated - EXPECT_EQ(result.interpolated_pose.header.stamp.sec, 15); - EXPECT_EQ(result.interpolated_pose.header.stamp.nanosec, static_cast(0)); - EXPECT_EQ(result.interpolated_pose.pose.pose.position.x, 15.0); - EXPECT_EQ(result.interpolated_pose.pose.pose.position.y, 30.0); - EXPECT_EQ(result.interpolated_pose.pose.pose.position.z, 0.0); - const auto rpy = autoware::localization_util::get_rpy(result.interpolated_pose.pose.pose); - EXPECT_NEAR(rpy.x * 180 / M_PI, 0.0, 1e-6); - EXPECT_NEAR(rpy.y * 180 / M_PI, 0.0, 1e-6); - EXPECT_NEAR(rpy.z * 180 / M_PI, 45.0, 1e-6); -} - -int main(int argc, char ** argv) -{ - rclcpp::init(argc, argv); - ::testing::InitGoogleTest(&argc, argv); - int result = RUN_ALL_TESTS(); - rclcpp::shutdown(); - return result; -} diff --git a/localization/autoware_localization_util/test/test_tpe.cpp b/localization/autoware_localization_util/test/test_tpe.cpp deleted file mode 100644 index 2d71a385246b7..0000000000000 --- a/localization/autoware_localization_util/test/test_tpe.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2023 The Autoware Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/localization_util/tree_structured_parzen_estimator.hpp" - -#include - -#include -#include -#include -#include -#include - -using TreeStructuredParzenEstimator = autoware::localization_util::TreeStructuredParzenEstimator; - -TEST(TreeStructuredParzenEstimatorTest, TPE_is_better_than_random_search_on_sphere_function) -{ - auto sphere_function = [](const TreeStructuredParzenEstimator::Input & input) { - double value = 0.0; - const auto n = static_cast(input.size()); - for (int64_t i = 0; i < n; i++) { - const double v = input[i] * 10; - value += v * v; - } - return value; - }; - - constexpr int64_t k_outer_trials_num = 20; - constexpr int64_t k_inner_trials_num = 200; - std::cout << std::fixed; - std::vector mean_scores; - std::vector sample_mean(5, 0.0); - std::vector sample_stddev{1.0, 1.0, 0.1, 0.1, 0.1}; - - for (const int64_t n_startup_trials : {k_inner_trials_num, k_inner_trials_num / 2}) { - const std::string method = ((n_startup_trials == k_inner_trials_num) ? "Random" : "TPE"); - - std::vector scores; - for (int64_t i = 0; i < k_outer_trials_num; i++) { - double best_score = std::numeric_limits::lowest(); - TreeStructuredParzenEstimator estimator( - TreeStructuredParzenEstimator::Direction::MAXIMIZE, n_startup_trials, sample_mean, - sample_stddev); - for (int64_t trial = 0; trial < k_inner_trials_num; trial++) { - const TreeStructuredParzenEstimator::Input input = estimator.get_next_input(); - const double score = -sphere_function(input); - estimator.add_trial({input, score}); - best_score = std::max(best_score, score); - } - scores.push_back(best_score); - } - - const double sum = std::accumulate(scores.begin(), scores.end(), 0.0); - const double mean = sum / static_cast(scores.size()); - mean_scores.push_back(mean); - double sq_sum = std::accumulate( - scores.begin(), scores.end(), 0.0, - [mean](double total, double score) { return total + (score - mean) * (score - mean); }); - const double stddev = std::sqrt(sq_sum / static_cast(scores.size())); - - std::cout << method << ", mean = " << mean << ", stddev = " << stddev << std::endl; - } - ASSERT_LT(mean_scores[0], mean_scores[1]); -} From 557a71e16695083aa40091b60f17c1daa90a257d Mon Sep 17 00:00:00 2001 From: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:52:13 +0900 Subject: [PATCH 18/61] fix(dummy_infrastructure): fix bugprone-reserved-identifier (#9919) Signed-off-by: kobayu858 Co-authored-by: kobayu858 --- .../src/dummy_infrastructure_node/dummy_infrastructure_node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/dummy_infrastructure/src/dummy_infrastructure_node/dummy_infrastructure_node.cpp b/system/dummy_infrastructure/src/dummy_infrastructure_node/dummy_infrastructure_node.cpp index 485d85c926268..4760c9366da46 100644 --- a/system/dummy_infrastructure/src/dummy_infrastructure_node/dummy_infrastructure_node.cpp +++ b/system/dummy_infrastructure/src/dummy_infrastructure_node/dummy_infrastructure_node.cpp @@ -24,7 +24,6 @@ using namespace std::literals; using std::chrono::duration; using std::chrono::duration_cast; using std::chrono::nanoseconds; -using std::placeholders::_1; namespace dummy_infrastructure { @@ -84,6 +83,7 @@ boost::optional findCommand( DummyInfrastructureNode::DummyInfrastructureNode(const rclcpp::NodeOptions & node_options) : Node("dummy_infrastructure", node_options) { + using std::placeholders::_1; // Parameter Server set_param_res_ = this->add_on_set_parameters_callback(std::bind(&DummyInfrastructureNode::onSetParam, this, _1)); From 6939a3da23a41781a6d973a8267e2ea1cb3a600d Mon Sep 17 00:00:00 2001 From: NorahXiong <103234047+NorahXiong@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:57:09 +0800 Subject: [PATCH 19/61] feat(autoware_qp_interface): porting autoware_qp_interface package to autoware.core (#9824) Signed-off-by: NorahXiong --- common/autoware_qp_interface/CHANGELOG.rst | 81 ---- common/autoware_qp_interface/CMakeLists.txt | 64 --- .../design/qp_interface-design.md | 48 --- .../qp_interface/osqp_csc_matrix_conv.hpp | 46 -- .../autoware/qp_interface/osqp_interface.hpp | 147 ------- .../qp_interface/proxqp_interface.hpp | 57 --- .../autoware/qp_interface/qp_interface.hpp | 61 --- common/autoware_qp_interface/package.xml | 30 -- .../src/osqp_csc_matrix_conv.cpp | 134 ------ .../src/osqp_interface.cpp | 394 ------------------ .../src/proxqp_interface.cpp | 157 ------- .../src/qp_interface.cpp | 70 ---- .../test/test_csc_matrix_conv.cpp | 181 -------- .../test/test_osqp_interface.cpp | 170 -------- .../test/test_proxqp_interface.cpp | 85 ---- 15 files changed, 1725 deletions(-) delete mode 100644 common/autoware_qp_interface/CHANGELOG.rst delete mode 100644 common/autoware_qp_interface/CMakeLists.txt delete mode 100644 common/autoware_qp_interface/design/qp_interface-design.md delete mode 100644 common/autoware_qp_interface/include/autoware/qp_interface/osqp_csc_matrix_conv.hpp delete mode 100644 common/autoware_qp_interface/include/autoware/qp_interface/osqp_interface.hpp delete mode 100644 common/autoware_qp_interface/include/autoware/qp_interface/proxqp_interface.hpp delete mode 100644 common/autoware_qp_interface/include/autoware/qp_interface/qp_interface.hpp delete mode 100644 common/autoware_qp_interface/package.xml delete mode 100644 common/autoware_qp_interface/src/osqp_csc_matrix_conv.cpp delete mode 100644 common/autoware_qp_interface/src/osqp_interface.cpp delete mode 100644 common/autoware_qp_interface/src/proxqp_interface.cpp delete mode 100644 common/autoware_qp_interface/src/qp_interface.cpp delete mode 100644 common/autoware_qp_interface/test/test_csc_matrix_conv.cpp delete mode 100644 common/autoware_qp_interface/test/test_osqp_interface.cpp delete mode 100644 common/autoware_qp_interface/test/test_proxqp_interface.cpp diff --git a/common/autoware_qp_interface/CHANGELOG.rst b/common/autoware_qp_interface/CHANGELOG.rst deleted file mode 100644 index f76dac861e1e6..0000000000000 --- a/common/autoware_qp_interface/CHANGELOG.rst +++ /dev/null @@ -1,81 +0,0 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Changelog for package autoware_qp_interface -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -0.40.0 (2024-12-12) -------------------- -* Merge branch 'main' into release-0.40.0 -* Revert "chore(package.xml): bump version to 0.39.0 (`#9587 `_)" - This reverts commit c9f0f2688c57b0f657f5c1f28f036a970682e7f5. -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* chore(package.xml): bump version to 0.39.0 (`#9587 `_) - * chore(package.xml): bump version to 0.39.0 - * fix: fix ticket links in CHANGELOG.rst - * fix: remove unnecessary diff - --------- - Co-authored-by: Yutaka Kondo -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* fix(cpplint): include what you use - common (`#9564 `_) -* fix: fix package names in changelog files (`#9500 `_) -* fix(autoware_osqp_interface): fix clang-tidy errors (`#9440 `_) -* 0.39.0 -* update changelog -* Merge commit '6a1ddbd08bd' into release-0.39.0 -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* refactor(qp_interface): prefix package and namespace with autoware (`#9236 `_) -* Contributors: Esteve Fernandez, Fumiya Watanabe, M. Fatih Cırıt, Ryohsuke Mitsudome, Ryuta Kambe, Yutaka Kondo - -0.39.0 (2024-11-25) -------------------- -* Merge commit '6a1ddbd08bd' into release-0.39.0 -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* refactor(qp_interface): prefix package and namespace with autoware (`#9236 `_) -* Contributors: Esteve Fernandez, Yutaka Kondo - -0.38.0 (2024-11-08) -------------------- -* unify package.xml version to 0.37.0 -* fix(qp_interface): fix unreadVariable (`#8349 `_) - * fix:unreadVariable - * fix:unreadVariable - * fix:unreadVariable - --------- -* perf(velocity_smoother): use ProxQP for faster optimization (`#8028 `_) - * perf(velocity_smoother): use ProxQP for faster optimization - * consider max_iteration - * disable warm start - * fix test - --------- -* refactor(qp_interface): clean up the code (`#8029 `_) - * refactor qp_interface - * variable names: m_XXX -> XXX\_ - * update - * update - --------- -* fix(fake_test_node, osqp_interface, qp_interface): remove unnecessary cppcheck inline suppressions (`#7855 `_) - * fix(fake_test_node, osqp_interface, qp_interface): remove unnecessary cppcheck inline suppressions - * style(pre-commit): autofix - --------- - Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> -* Contributors: Ryuta Kambe, Takayuki Murooka, Yutaka Kondo, kobayu858 - -0.26.0 (2024-04-03) -------------------- -* feat(qp_interface): support proxqp (`#3699 `_) - * feat(qp_interface): add proxqp interface - * update - --------- -* feat(qp_interface): add new package which will contain various qp solvers (`#3697 `_) -* Contributors: Takayuki Murooka diff --git a/common/autoware_qp_interface/CMakeLists.txt b/common/autoware_qp_interface/CMakeLists.txt deleted file mode 100644 index 1df75d2d719a0..0000000000000 --- a/common/autoware_qp_interface/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(autoware_qp_interface) - -find_package(autoware_cmake REQUIRED) -autoware_package() - -find_package(Eigen3 REQUIRED) -find_package(proxsuite REQUIRED) - -# after find_package(osqp_vendor) in ament_auto_find_build_dependencies -find_package(osqp REQUIRED) -get_target_property(OSQP_INCLUDE_SUB_DIR osqp::osqp INTERFACE_INCLUDE_DIRECTORIES) -get_filename_component(OSQP_INCLUDE_DIR ${OSQP_INCLUDE_SUB_DIR} PATH) - -set(QP_INTERFACE_LIB_SRC - src/qp_interface.cpp - src/osqp_interface.cpp - src/osqp_csc_matrix_conv.cpp - src/proxqp_interface.cpp -) - -set(QP_INTERFACE_LIB_HEADERS - include/autoware/qp_interface/qp_interface.hpp - include/autoware/qp_interface/osqp_interface.hpp - include/autoware/qp_interface/osqp_csc_matrix_conv.hpp - include/autoware/qp_interface/proxqp_interface.hpp -) - -ament_auto_add_library(${PROJECT_NAME} SHARED - ${QP_INTERFACE_LIB_SRC} - ${QP_INTERFACE_LIB_HEADERS} -) -target_compile_options(${PROJECT_NAME} PRIVATE -Wno-error=old-style-cast) - -target_include_directories(${PROJECT_NAME} - SYSTEM PUBLIC - "${OSQP_INCLUDE_DIR}" - "${EIGEN3_INCLUDE_DIR}" -) - -ament_target_dependencies(${PROJECT_NAME} - Eigen3 - osqp_vendor - proxsuite -) - -# crucial so downstream package builds because osqp_interface exposes osqp.hpp -ament_export_include_directories("${OSQP_INCLUDE_DIR}") -# crucial so the linking order is correct in a downstream package: libosqp_interface.a should come before libosqp.a -ament_export_libraries(osqp::osqp) - -if(BUILD_TESTING) - set(TEST_SOURCES - test/test_osqp_interface.cpp - test/test_csc_matrix_conv.cpp - test/test_proxqp_interface.cpp - ) - set(TEST_OSQP_INTERFACE_EXE test_osqp_interface) - ament_add_ros_isolated_gtest(${TEST_OSQP_INTERFACE_EXE} ${TEST_SOURCES}) - target_link_libraries(${TEST_OSQP_INTERFACE_EXE} ${PROJECT_NAME}) -endif() - -ament_auto_package(INSTALL_TO_SHARE -) diff --git a/common/autoware_qp_interface/design/qp_interface-design.md b/common/autoware_qp_interface/design/qp_interface-design.md deleted file mode 100644 index edc7fa9845206..0000000000000 --- a/common/autoware_qp_interface/design/qp_interface-design.md +++ /dev/null @@ -1,48 +0,0 @@ -# Interface for QP solvers - -This is the design document for the `autoware_qp_interface` package. - -## Purpose / Use cases - -This packages provides a C++ interface for QP solvers. -Currently, supported QP solvers are - -- [OSQP library](https://osqp.org/docs/solver/index.html) - -## Design - -The class `QPInterface` takes a problem formulation as Eigen matrices and vectors, converts these objects into -C-style Compressed-Column-Sparse matrices and dynamic arrays, loads the data into the QP workspace dataholder, and runs the optimizer. - -## Inputs / Outputs / API - -The interface can be used in several ways: - -1. Initialize the interface, and load the problem formulation at the optimization call. - - ```cpp - QPInterface qp_interface; - qp_interface.optimize(P, A, q, l, u); - ``` - -2. WARM START OPTIMIZATION by modifying the problem formulation between optimization runs. - - ```cpp - QPInterface qp_interface(true); - qp_interface.optimize(P, A, q, l, u); - qp_interface.optimize(P_new, A_new, q_new, l_new, u_new); - ``` - - The optimization results are returned as a vector by the optimization function. - - ```cpp - const auto solution = qp_interface.optimize(); - double x_0 = solution[0]; - double x_1 = solution[1]; - ``` - -## References / External links - -- OSQP library: - -## Related issues diff --git a/common/autoware_qp_interface/include/autoware/qp_interface/osqp_csc_matrix_conv.hpp b/common/autoware_qp_interface/include/autoware/qp_interface/osqp_csc_matrix_conv.hpp deleted file mode 100644 index 9575d9d18c69f..0000000000000 --- a/common/autoware_qp_interface/include/autoware/qp_interface/osqp_csc_matrix_conv.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__QP_INTERFACE__OSQP_CSC_MATRIX_CONV_HPP_ -#define AUTOWARE__QP_INTERFACE__OSQP_CSC_MATRIX_CONV_HPP_ - -#include "osqp/glob_opts.h" - -#include - -#include - -namespace autoware::qp_interface -{ -/// \brief Compressed-Column-Sparse Matrix -struct CSC_Matrix -{ - /// Vector of non-zero values. Ex: [4,1,1,2] - std::vector vals_; - /// Vector of row index corresponding to values. Ex: [0, 1, 0, 1] (Eigen: 'inner') - std::vector row_idxs_; - /// Vector of 'val' indices where each column starts. Ex: [0, 2, 4] (Eigen: 'outer') - std::vector col_idxs_; -}; - -/// \brief Calculate CSC matrix from Eigen matrix -CSC_Matrix calCSCMatrix(const Eigen::MatrixXd & mat); -/// \brief Calculate upper trapezoidal CSC matrix from square Eigen matrix -CSC_Matrix calCSCMatrixTrapezoidal(const Eigen::MatrixXd & mat); -/// \brief Print the given CSC matrix to the standard output -void printCSCMatrix(const CSC_Matrix & csc_mat); - -} // namespace autoware::qp_interface - -#endif // AUTOWARE__QP_INTERFACE__OSQP_CSC_MATRIX_CONV_HPP_ diff --git a/common/autoware_qp_interface/include/autoware/qp_interface/osqp_interface.hpp b/common/autoware_qp_interface/include/autoware/qp_interface/osqp_interface.hpp deleted file mode 100644 index a5777dd545e9f..0000000000000 --- a/common/autoware_qp_interface/include/autoware/qp_interface/osqp_interface.hpp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__QP_INTERFACE__OSQP_INTERFACE_HPP_ -#define AUTOWARE__QP_INTERFACE__OSQP_INTERFACE_HPP_ - -#include "autoware/qp_interface/osqp_csc_matrix_conv.hpp" -#include "autoware/qp_interface/qp_interface.hpp" -#include "osqp/osqp.h" - -#include -#include -#include -#include - -namespace autoware::qp_interface -{ -constexpr c_float OSQP_INF = 1e30; - -class OSQPInterface : public QPInterface -{ -public: - /// \brief Constructor without problem formulation - OSQPInterface( - const bool enable_warm_start = false, const int max_iteration = 20000, - const c_float eps_abs = std::numeric_limits::epsilon(), - const c_float eps_rel = std::numeric_limits::epsilon(), const bool polish = true, - const bool verbose = false); - /// \brief Constructor with problem setup - /// \param P: (n,n) matrix defining relations between parameters. - /// \param A: (m,n) matrix defining parameter constraints relative to the lower and upper bound. - /// \param q: (n) vector defining the linear cost of the problem. - /// \param l: (m) vector defining the lower bound problem constraint. - /// \param u: (m) vector defining the upper bound problem constraint. - /// \param eps_abs: Absolute convergence tolerance. - OSQPInterface( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u, - const bool enable_warm_start = false, - const c_float eps_abs = std::numeric_limits::epsilon()); - OSQPInterface( - const CSC_Matrix & P, const CSC_Matrix & A, const std::vector & q, - const std::vector & l, const std::vector & u, - const bool enable_warm_start = false, - const c_float eps_abs = std::numeric_limits::epsilon()); - ~OSQPInterface(); - - static void OSQPWorkspaceDeleter(OSQPWorkspace * ptr) noexcept; - - std::vector optimize( - CSC_Matrix P, CSC_Matrix A, const std::vector & q, const std::vector & l, - const std::vector & u); - - int getIterationNumber() const override; - bool isSolved() const override; - std::string getStatus() const override; - - int getPolishStatus() const; - std::vector getDualSolution() const; - - void updateEpsAbs(const double eps_abs) override; - void updateEpsRel(const double eps_rel) override; - void updateVerbose(const bool verbose) override; - - // Updates problem parameters while keeping solution in memory. - // - // Args: - // P_new: (n,n) matrix defining relations between parameters. - // A_new: (m,n) matrix defining parameter constraints relative to the lower and upper bound. - // q_new: (n) vector defining the linear cost of the problem. - // l_new: (m) vector defining the lower bound problem constraint. - // u_new: (m) vector defining the upper bound problem constraint. - void updateP(const Eigen::MatrixXd & P_new); - void updateCscP(const CSC_Matrix & P_csc); - void updateA(const Eigen::MatrixXd & A_new); - void updateCscA(const CSC_Matrix & A_csc); - void updateQ(const std::vector & q_new); - void updateL(const std::vector & l_new); - void updateU(const std::vector & u_new); - void updateBounds(const std::vector & l_new, const std::vector & u_new); - - void updateMaxIter(const int iter); - void updateRhoInterval(const int rho_interval); - void updateRho(const double rho); - void updateAlpha(const double alpha); - void updateScaling(const int scaling); - void updatePolish(const bool polish); - void updatePolishRefinementIteration(const int polish_refine_iter); - void updateCheckTermination(const int check_termination); - - /// \brief Get the number of iteration taken to solve the problem - inline int64_t getTakenIter() const { return static_cast(latest_work_info_.iter); } - /// \brief Get the status message for the latest problem solved - inline std::string getStatusMessage() const - { - return static_cast(latest_work_info_.status); - } - /// \brief Get the runtime of the latest problem solved - inline double getRunTime() const { return latest_work_info_.run_time; } - /// \brief Get the objective value the latest problem solved - inline double getObjVal() const { return latest_work_info_.obj_val; } - /// \brief Returns flag asserting interface condition (Healthy condition: 0). - inline int64_t getExitFlag() const { return exitflag_; } - - // Setter functions for warm start - bool setWarmStart( - const std::vector & primal_variables, const std::vector & dual_variables); - bool setPrimalVariables(const std::vector & primal_variables); - bool setDualVariables(const std::vector & dual_variables); - -private: - std::unique_ptr> work_; - std::unique_ptr settings_; - std::unique_ptr data_; - // store last work info since work is cleaned up at every execution to prevent memory leak. - OSQPInfo latest_work_info_; - // Number of parameters to optimize - int64_t param_n_; - // Flag to check if the current work exists - bool work__initialized = false; - // Exitflag - int64_t exitflag_; - - void initializeProblemImpl( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) override; - - void initializeCSCProblemImpl( - CSC_Matrix P, CSC_Matrix A, const std::vector & q, const std::vector & l, - const std::vector & u); - - std::vector optimizeImpl() override; -}; -} // namespace autoware::qp_interface - -#endif // AUTOWARE__QP_INTERFACE__OSQP_INTERFACE_HPP_ diff --git a/common/autoware_qp_interface/include/autoware/qp_interface/proxqp_interface.hpp b/common/autoware_qp_interface/include/autoware/qp_interface/proxqp_interface.hpp deleted file mode 100644 index 324da4b18c6fd..0000000000000 --- a/common/autoware_qp_interface/include/autoware/qp_interface/proxqp_interface.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__QP_INTERFACE__PROXQP_INTERFACE_HPP_ -#define AUTOWARE__QP_INTERFACE__PROXQP_INTERFACE_HPP_ - -#include "autoware/qp_interface/qp_interface.hpp" - -#include -#include - -#include -#include -#include -#include - -namespace autoware::qp_interface -{ -class ProxQPInterface : public QPInterface -{ -public: - explicit ProxQPInterface( - const bool enable_warm_start, const int max_iteration, const double eps_abs, - const double eps_rel, const bool verbose = false); - - int getIterationNumber() const override; - bool isSolved() const override; - std::string getStatus() const override; - - void updateEpsAbs(const double eps_abs) override; - void updateEpsRel(const double eps_rel) override; - void updateVerbose(const bool verbose) override; - -private: - proxsuite::proxqp::Settings settings_{}; - std::shared_ptr> qp_ptr_{nullptr}; - - void initializeProblemImpl( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) override; - - std::vector optimizeImpl() override; -}; -} // namespace autoware::qp_interface - -#endif // AUTOWARE__QP_INTERFACE__PROXQP_INTERFACE_HPP_ diff --git a/common/autoware_qp_interface/include/autoware/qp_interface/qp_interface.hpp b/common/autoware_qp_interface/include/autoware/qp_interface/qp_interface.hpp deleted file mode 100644 index be3c598512bf6..0000000000000 --- a/common/autoware_qp_interface/include/autoware/qp_interface/qp_interface.hpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__QP_INTERFACE__QP_INTERFACE_HPP_ -#define AUTOWARE__QP_INTERFACE__QP_INTERFACE_HPP_ - -#include - -#include -#include -#include - -namespace autoware::qp_interface -{ -class QPInterface -{ -public: - explicit QPInterface(const bool enable_warm_start) : enable_warm_start_(enable_warm_start) {} - - std::vector optimize( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u); - - virtual bool isSolved() const = 0; - virtual int getIterationNumber() const = 0; - virtual std::string getStatus() const = 0; - - virtual void updateEpsAbs([[maybe_unused]] const double eps_abs) = 0; - virtual void updateEpsRel([[maybe_unused]] const double eps_rel) = 0; - virtual void updateVerbose([[maybe_unused]] const bool verbose) {} - -protected: - bool enable_warm_start_{false}; - - void initializeProblem( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u); - - virtual void initializeProblemImpl( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) = 0; - - virtual std::vector optimizeImpl() = 0; - - std::optional variables_num_{std::nullopt}; - std::optional constraints_num_{std::nullopt}; -}; -} // namespace autoware::qp_interface - -#endif // AUTOWARE__QP_INTERFACE__QP_INTERFACE_HPP_ diff --git a/common/autoware_qp_interface/package.xml b/common/autoware_qp_interface/package.xml deleted file mode 100644 index b61d03a36db72..0000000000000 --- a/common/autoware_qp_interface/package.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - autoware_qp_interface - 0.40.0 - Interface for the QP solvers - Takayuki Murooka - Fumiya Watanabe - Maxime CLEMENT - Satoshi Ota - Apache 2.0 - - ament_cmake_auto - autoware_cmake - - eigen - osqp_vendor - proxsuite - rclcpp - rclcpp_components - - ament_cmake_ros - ament_lint_auto - autoware_lint_common - eigen - - - ament_cmake - - diff --git a/common/autoware_qp_interface/src/osqp_csc_matrix_conv.cpp b/common/autoware_qp_interface/src/osqp_csc_matrix_conv.cpp deleted file mode 100644 index 15314a9e4a5fa..0000000000000 --- a/common/autoware_qp_interface/src/osqp_csc_matrix_conv.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/qp_interface/osqp_csc_matrix_conv.hpp" - -#include -#include - -#include -#include -#include - -namespace autoware::qp_interface -{ -CSC_Matrix calCSCMatrix(const Eigen::MatrixXd & mat) -{ - const size_t elem = static_cast(mat.nonZeros()); - const Eigen::Index rows = mat.rows(); - const Eigen::Index cols = mat.cols(); - - std::vector vals; - vals.reserve(elem); - std::vector row_idxs; - row_idxs.reserve(elem); - std::vector col_idxs; - col_idxs.reserve(elem); - - // Construct CSC matrix arrays - c_float val; - c_int elem_count = 0; - - col_idxs.push_back(0); - - for (Eigen::Index j = 0; j < cols; j++) { // col iteration - for (Eigen::Index i = 0; i < rows; i++) { // row iteration - // Get values of nonzero elements - val = mat(i, j); - if (std::fabs(val) < 1e-9) { - continue; - } - elem_count += 1; - - // Store values - vals.push_back(val); - row_idxs.push_back(i); - } - - col_idxs.push_back(elem_count); - } - - CSC_Matrix csc_matrix = {vals, row_idxs, col_idxs}; - - return csc_matrix; -} - -CSC_Matrix calCSCMatrixTrapezoidal(const Eigen::MatrixXd & mat) -{ - const size_t elem = static_cast(mat.nonZeros()); - const Eigen::Index rows = mat.rows(); - const Eigen::Index cols = mat.cols(); - - if (rows != cols) { - throw std::invalid_argument("Matrix must be square (n, n)"); - } - - std::vector vals; - vals.reserve(elem); - std::vector row_idxs; - row_idxs.reserve(elem); - std::vector col_idxs; - col_idxs.reserve(elem); - - // Construct CSC matrix arrays - c_float val; - Eigen::Index trap_last_idx = 0; - c_int elem_count = 0; - - col_idxs.push_back(0); - - for (Eigen::Index j = 0; j < cols; j++) { // col iteration - for (Eigen::Index i = 0; i <= trap_last_idx; i++) { // row iteration - // Get values of nonzero elements - val = mat(i, j); - if (std::fabs(val) < 1e-9) { - continue; - } - elem_count += 1; - - // Store values - vals.push_back(val); - row_idxs.push_back(i); - } - - col_idxs.push_back(elem_count); - trap_last_idx += 1; - } - - CSC_Matrix csc_matrix = {vals, row_idxs, col_idxs}; - - return csc_matrix; -} - -void printCSCMatrix(const CSC_Matrix & csc_mat) -{ - std::cout << "["; - for (const c_float & val : csc_mat.vals_) { - std::cout << val << ", "; - } - std::cout << "]\n"; - - std::cout << "["; - for (const c_int & row : csc_mat.row_idxs_) { - std::cout << row << ", "; - } - std::cout << "]\n"; - - std::cout << "["; - for (const c_int & col : csc_mat.col_idxs_) { - std::cout << col << ", "; - } - std::cout << "]\n"; -} -} // namespace autoware::qp_interface diff --git a/common/autoware_qp_interface/src/osqp_interface.cpp b/common/autoware_qp_interface/src/osqp_interface.cpp deleted file mode 100644 index fbb8e71f4c251..0000000000000 --- a/common/autoware_qp_interface/src/osqp_interface.cpp +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/qp_interface/osqp_interface.hpp" - -#include "autoware/qp_interface/osqp_csc_matrix_conv.hpp" - -#include - -#include -#include -#include -#include - -namespace autoware::qp_interface -{ -OSQPInterface::OSQPInterface( - const bool enable_warm_start, const int max_iteration, const c_float eps_abs, - const c_float eps_rel, const bool polish, const bool verbose) -: QPInterface(enable_warm_start), work_{nullptr, OSQPWorkspaceDeleter} -{ - settings_ = std::make_unique(); - data_ = std::make_unique(); - - if (settings_) { - osqp_set_default_settings(settings_.get()); - settings_->alpha = 1.6; // Change alpha parameter - settings_->eps_rel = eps_rel; - settings_->eps_abs = eps_abs; - settings_->eps_prim_inf = 1.0E-4; - settings_->eps_dual_inf = 1.0E-4; - settings_->warm_start = enable_warm_start; - settings_->max_iter = max_iteration; - settings_->verbose = verbose; - settings_->polish = polish; - } - exitflag_ = 0; -} - -OSQPInterface::OSQPInterface( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u, const bool enable_warm_start, - const c_float eps_abs) -: OSQPInterface(enable_warm_start, eps_abs) -{ - initializeProblem(P, A, q, l, u); -} - -OSQPInterface::OSQPInterface( - const CSC_Matrix & P, const CSC_Matrix & A, const std::vector & q, - const std::vector & l, const std::vector & u, const bool enable_warm_start, - const c_float eps_abs) -: OSQPInterface(enable_warm_start, eps_abs) -{ - initializeCSCProblemImpl(P, A, q, l, u); -} - -OSQPInterface::~OSQPInterface() -{ - if (data_->P) free(data_->P); - if (data_->A) free(data_->A); -} - -void OSQPInterface::initializeProblemImpl( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) -{ - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - initializeCSCProblemImpl(P_csc, A_csc, q, l, u); -} - -void OSQPInterface::initializeCSCProblemImpl( - CSC_Matrix P_csc, CSC_Matrix A_csc, const std::vector & q, const std::vector & l, - const std::vector & u) -{ - // Dynamic float arrays - std::vector q_tmp(q.begin(), q.end()); - std::vector l_tmp(l.begin(), l.end()); - std::vector u_tmp(u.begin(), u.end()); - double * q_dyn = q_tmp.data(); - double * l_dyn = l_tmp.data(); - double * u_dyn = u_tmp.data(); - - /********************** - * OBJECTIVE FUNCTION - **********************/ - param_n_ = static_cast(q.size()); - data_->m = static_cast(l.size()); - - /***************** - * POPULATE DATA - *****************/ - data_->n = param_n_; - if (data_->P) free(data_->P); - data_->P = csc_matrix( - data_->n, data_->n, static_cast(P_csc.vals_.size()), P_csc.vals_.data(), - P_csc.row_idxs_.data(), P_csc.col_idxs_.data()); - data_->q = q_dyn; - if (data_->A) free(data_->A); - data_->A = csc_matrix( - data_->m, data_->n, static_cast(A_csc.vals_.size()), A_csc.vals_.data(), - A_csc.row_idxs_.data(), A_csc.col_idxs_.data()); - data_->l = l_dyn; - data_->u = u_dyn; - - // Setup workspace - OSQPWorkspace * workspace; - exitflag_ = osqp_setup(&workspace, data_.get(), settings_.get()); - work_.reset(workspace); - work__initialized = true; -} - -void OSQPInterface::OSQPWorkspaceDeleter(OSQPWorkspace * ptr) noexcept -{ - if (ptr != nullptr) { - osqp_cleanup(ptr); - } -} - -void OSQPInterface::updateEpsAbs(const double eps_abs) -{ - settings_->eps_abs = eps_abs; // for default setting - if (work__initialized) { - osqp_update_eps_abs(work_.get(), eps_abs); // for current work - } -} - -void OSQPInterface::updateEpsRel(const double eps_rel) -{ - settings_->eps_rel = eps_rel; // for default setting - if (work__initialized) { - osqp_update_eps_rel(work_.get(), eps_rel); // for current work - } -} - -void OSQPInterface::updateMaxIter(const int max_iter) -{ - settings_->max_iter = max_iter; // for default setting - if (work__initialized) { - osqp_update_max_iter(work_.get(), max_iter); // for current work - } -} - -void OSQPInterface::updateVerbose(const bool is_verbose) -{ - settings_->verbose = is_verbose; // for default setting - if (work__initialized) { - osqp_update_verbose(work_.get(), is_verbose); // for current work - } -} - -void OSQPInterface::updateRhoInterval(const int rho_interval) -{ - settings_->adaptive_rho_interval = rho_interval; // for default setting -} - -void OSQPInterface::updateRho(const double rho) -{ - settings_->rho = rho; - if (work__initialized) { - osqp_update_rho(work_.get(), rho); - } -} - -void OSQPInterface::updateAlpha(const double alpha) -{ - settings_->alpha = alpha; - if (work__initialized) { - osqp_update_alpha(work_.get(), alpha); - } -} - -void OSQPInterface::updateScaling(const int scaling) -{ - settings_->scaling = scaling; -} - -void OSQPInterface::updatePolish(const bool polish) -{ - settings_->polish = polish; - if (work__initialized) { - osqp_update_polish(work_.get(), polish); - } -} - -void OSQPInterface::updatePolishRefinementIteration(const int polish_refine_iter) -{ - if (polish_refine_iter < 0) { - std::cerr << "Polish refinement iterations must be positive" << std::endl; - return; - } - - settings_->polish_refine_iter = polish_refine_iter; - if (work__initialized) { - osqp_update_polish_refine_iter(work_.get(), polish_refine_iter); - } -} - -void OSQPInterface::updateCheckTermination(const int check_termination) -{ - if (check_termination < 0) { - std::cerr << "Check termination must be positive" << std::endl; - return; - } - - settings_->check_termination = check_termination; - if (work__initialized) { - osqp_update_check_termination(work_.get(), check_termination); - } -} - -bool OSQPInterface::setWarmStart( - const std::vector & primal_variables, const std::vector & dual_variables) -{ - return setPrimalVariables(primal_variables) && setDualVariables(dual_variables); -} - -bool OSQPInterface::setPrimalVariables(const std::vector & primal_variables) -{ - if (!work__initialized) { - return false; - } - - const auto result = osqp_warm_start_x(work_.get(), primal_variables.data()); - if (result != 0) { - std::cerr << "Failed to set primal variables for warm start" << std::endl; - return false; - } - - return true; -} - -bool OSQPInterface::setDualVariables(const std::vector & dual_variables) -{ - if (!work__initialized) { - return false; - } - - const auto result = osqp_warm_start_y(work_.get(), dual_variables.data()); - if (result != 0) { - std::cerr << "Failed to set dual variables for warm start" << std::endl; - return false; - } - - return true; -} - -void OSQPInterface::updateP(const Eigen::MatrixXd & P_new) -{ - /* - // Transform 'P' into an 'upper trapezoidal matrix' - Eigen::MatrixXd P_trap = P_new.triangularView(); - // Transform 'P' into a sparse matrix and extract data as dynamic arrays - Eigen::SparseMatrix P_sparse = P_trap.sparseView(); - double *P_val_ptr = P_sparse.valuePtr(); - // Convert dynamic 'int' arrays to 'c_int' arrays (OSQP input type) - c_int P_elem_N = P_sparse.nonZeros(); - */ - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P_new); - osqp_update_P(work_.get(), P_csc.vals_.data(), OSQP_NULL, static_cast(P_csc.vals_.size())); -} - -void OSQPInterface::updateCscP(const CSC_Matrix & P_csc) -{ - osqp_update_P(work_.get(), P_csc.vals_.data(), OSQP_NULL, static_cast(P_csc.vals_.size())); -} - -void OSQPInterface::updateA(const Eigen::MatrixXd & A_new) -{ - /* - // Transform 'A' into a sparse matrix and extract data as dynamic arrays - Eigen::SparseMatrix A_sparse = A_new.sparseView(); - double *A_val_ptr = A_sparse.valuePtr(); - // Convert dynamic 'int' arrays to 'c_int' arrays (OSQP input type) - c_int A_elem_N = A_sparse.nonZeros(); - */ - CSC_Matrix A_csc = calCSCMatrix(A_new); - osqp_update_A(work_.get(), A_csc.vals_.data(), OSQP_NULL, static_cast(A_csc.vals_.size())); - return; -} - -void OSQPInterface::updateCscA(const CSC_Matrix & A_csc) -{ - osqp_update_A(work_.get(), A_csc.vals_.data(), OSQP_NULL, static_cast(A_csc.vals_.size())); -} - -void OSQPInterface::updateQ(const std::vector & q_new) -{ - std::vector q_tmp(q_new.begin(), q_new.end()); - double * q_dyn = q_tmp.data(); - osqp_update_lin_cost(work_.get(), q_dyn); -} - -void OSQPInterface::updateL(const std::vector & l_new) -{ - std::vector l_tmp(l_new.begin(), l_new.end()); - double * l_dyn = l_tmp.data(); - osqp_update_lower_bound(work_.get(), l_dyn); -} - -void OSQPInterface::updateU(const std::vector & u_new) -{ - std::vector u_tmp(u_new.begin(), u_new.end()); - double * u_dyn = u_tmp.data(); - osqp_update_upper_bound(work_.get(), u_dyn); -} - -void OSQPInterface::updateBounds( - const std::vector & l_new, const std::vector & u_new) -{ - std::vector l_tmp(l_new.begin(), l_new.end()); - std::vector u_tmp(u_new.begin(), u_new.end()); - double * l_dyn = l_tmp.data(); - double * u_dyn = u_tmp.data(); - osqp_update_bounds(work_.get(), l_dyn, u_dyn); -} - -int OSQPInterface::getIterationNumber() const -{ - return work_->info->iter; -} - -std::string OSQPInterface::getStatus() const -{ - return "OSQP_SOLVED"; -} - -bool OSQPInterface::isSolved() const -{ - return latest_work_info_.status_val == 1; -} - -int OSQPInterface::getPolishStatus() const -{ - return static_cast(latest_work_info_.status_polish); -} - -std::vector OSQPInterface::getDualSolution() const -{ - double * sol_y = work_->solution->y; - std::vector dual_solution(sol_y, sol_y + data_->m); - return dual_solution; -} - -std::vector OSQPInterface::optimizeImpl() -{ - osqp_solve(work_.get()); - - double * sol_x = work_->solution->x; - std::vector sol_primal(sol_x, sol_x + param_n_); - - latest_work_info_ = *(work_->info); - - if (!enable_warm_start_) { - work_.reset(); - work__initialized = false; - } - - return sol_primal; -} - -std::vector OSQPInterface::optimize( - CSC_Matrix P, CSC_Matrix A, const std::vector & q, const std::vector & l, - const std::vector & u) -{ - initializeCSCProblemImpl(P, A, q, l, u); - const auto result = optimizeImpl(); - - // show polish status if not successful - const int status_polish = static_cast(latest_work_info_.status_polish); - if (status_polish != 1) { - const auto msg = status_polish == 0 ? "unperformed" - : status_polish == -1 ? "unsuccessful" - : "unknown"; - std::cerr << "osqp polish process failed : " << msg << ". The result may be inaccurate" - << std::endl; - } - - return result; -} - -} // namespace autoware::qp_interface diff --git a/common/autoware_qp_interface/src/proxqp_interface.cpp b/common/autoware_qp_interface/src/proxqp_interface.cpp deleted file mode 100644 index a0ebbf0db0510..0000000000000 --- a/common/autoware_qp_interface/src/proxqp_interface.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/qp_interface/proxqp_interface.hpp" - -#include -#include -#include - -namespace autoware::qp_interface -{ -using proxsuite::proxqp::QPSolverOutput; - -ProxQPInterface::ProxQPInterface( - const bool enable_warm_start, const int max_iteration, const double eps_abs, const double eps_rel, - const bool verbose) -: QPInterface(enable_warm_start) -{ - settings_.max_iter = max_iteration; - settings_.eps_abs = eps_abs; - settings_.eps_rel = eps_rel; - settings_.verbose = verbose; -} - -void ProxQPInterface::initializeProblemImpl( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) -{ - const size_t variables_num = q.size(); - const size_t constraints_num = l.size(); - - const bool enable_warm_start = [&]() { - if ( - !enable_warm_start_ // Warm start is designated - || !qp_ptr_ // QP pointer is initialized - // The number of variables is the same as the previous one. - || !variables_num_ || - *variables_num_ != variables_num - // The number of constraints is the same as the previous one - || !constraints_num_ || *constraints_num_ != constraints_num) { - return false; - } - return true; - }(); - - if (!enable_warm_start) { - qp_ptr_ = std::make_shared>( - variables_num, 0, constraints_num); - } - - settings_.initial_guess = - enable_warm_start ? proxsuite::proxqp::InitialGuessStatus::WARM_START_WITH_PREVIOUS_RESULT - : proxsuite::proxqp::InitialGuessStatus::NO_INITIAL_GUESS; - - qp_ptr_->settings = settings_; - - Eigen::SparseMatrix P_sparse(variables_num, constraints_num); - P_sparse = P.sparseView(); - - // NOTE: const std vector cannot be converted to eigen vector - std::vector non_const_q = q; - Eigen::VectorXd eigen_q = - Eigen::Map(non_const_q.data(), non_const_q.size()); - std::vector l_std_vec = l; - Eigen::VectorXd eigen_l = - Eigen::Map(l_std_vec.data(), l_std_vec.size()); - std::vector u_std_vec = u; - Eigen::VectorXd eigen_u = - Eigen::Map(u_std_vec.data(), u_std_vec.size()); - - if (enable_warm_start) { - qp_ptr_->update( - P_sparse, eigen_q, proxsuite::nullopt, proxsuite::nullopt, A.sparseView(), eigen_l, eigen_u); - } else { - qp_ptr_->init( - P_sparse, eigen_q, proxsuite::nullopt, proxsuite::nullopt, A.sparseView(), eigen_l, eigen_u); - } -} - -void ProxQPInterface::updateEpsAbs(const double eps_abs) -{ - settings_.eps_abs = eps_abs; -} - -void ProxQPInterface::updateEpsRel(const double eps_rel) -{ - settings_.eps_rel = eps_rel; -} - -void ProxQPInterface::updateVerbose(const bool is_verbose) -{ - settings_.verbose = is_verbose; -} - -bool ProxQPInterface::isSolved() const -{ - if (qp_ptr_) { - return qp_ptr_->results.info.status == QPSolverOutput::PROXQP_SOLVED; - } - return false; -} - -int ProxQPInterface::getIterationNumber() const -{ - if (qp_ptr_) { - return qp_ptr_->results.info.iter; - } - return 0; -} - -std::string ProxQPInterface::getStatus() const -{ - if (qp_ptr_) { - if (qp_ptr_->results.info.status == QPSolverOutput::PROXQP_SOLVED) { - return "PROXQP_SOLVED"; - } - if (qp_ptr_->results.info.status == QPSolverOutput::PROXQP_MAX_ITER_REACHED) { - return "PROXQP_MAX_ITER_REACHED"; - } - if (qp_ptr_->results.info.status == QPSolverOutput::PROXQP_PRIMAL_INFEASIBLE) { - return "PROXQP_PRIMAL_INFEASIBLE"; - } - // if (qp_ptr_->results.info.status == QPSolverOutput::PROXQP_SOLVED_CLOSEST_PRIMAL_FEASIBLE) { - // return "PROXQP_SOLVED_CLOSEST_PRIMAL_FEASIBLE"; - // } - if (qp_ptr_->results.info.status == QPSolverOutput::PROXQP_DUAL_INFEASIBLE) { - return "PROXQP_DUAL_INFEASIBLE"; - } - if (qp_ptr_->results.info.status == QPSolverOutput::PROXQP_NOT_RUN) { - return "PROXQP_NOT_RUN"; - } - } - return "None"; -} - -std::vector ProxQPInterface::optimizeImpl() -{ - qp_ptr_->solve(); - - std::vector result; - for (Eigen::Index i = 0; i < qp_ptr_->results.x.size(); ++i) { - result.push_back(qp_ptr_->results.x[i]); - } - return result; -} -} // namespace autoware::qp_interface diff --git a/common/autoware_qp_interface/src/qp_interface.cpp b/common/autoware_qp_interface/src/qp_interface.cpp deleted file mode 100644 index f01e57772dc4f..0000000000000 --- a/common/autoware_qp_interface/src/qp_interface.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/qp_interface/qp_interface.hpp" - -#include -#include -#include - -namespace autoware::qp_interface -{ -void QPInterface::initializeProblem( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) -{ - // check if arguments are valid - std::stringstream ss; - if (P.rows() != P.cols()) { - ss << "P.rows() and P.cols() are not the same. P.rows() = " << P.rows() - << ", P.cols() = " << P.cols(); - throw std::invalid_argument(ss.str()); - } - if (P.rows() != static_cast(q.size())) { - ss << "P.rows() and q.size() are not the same. P.rows() = " << P.rows() - << ", q.size() = " << q.size(); - throw std::invalid_argument(ss.str()); - } - if (P.rows() != A.cols()) { - ss << "P.rows() and A.cols() are not the same. P.rows() = " << P.rows() - << ", A.cols() = " << A.cols(); - throw std::invalid_argument(ss.str()); - } - if (A.rows() != static_cast(l.size())) { - ss << "A.rows() and l.size() are not the same. A.rows() = " << A.rows() - << ", l.size() = " << l.size(); - throw std::invalid_argument(ss.str()); - } - if (A.rows() != static_cast(u.size())) { - ss << "A.rows() and u.size() are not the same. A.rows() = " << A.rows() - << ", u.size() = " << u.size(); - throw std::invalid_argument(ss.str()); - } - - initializeProblemImpl(P, A, q, l, u); - - variables_num_ = q.size(); - constraints_num_ = l.size(); -} - -std::vector QPInterface::optimize( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) -{ - initializeProblem(P, A, q, l, u); - const auto result = optimizeImpl(); - - return result; -} -} // namespace autoware::qp_interface diff --git a/common/autoware_qp_interface/test/test_csc_matrix_conv.cpp b/common/autoware_qp_interface/test/test_csc_matrix_conv.cpp deleted file mode 100644 index 1f377a1a24535..0000000000000 --- a/common/autoware_qp_interface/test/test_csc_matrix_conv.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/qp_interface/osqp_csc_matrix_conv.hpp" -#include "gtest/gtest.h" - -#include - -#include -#include -#include - -TEST(TestCscMatrixConv, Nominal) -{ - using autoware::qp_interface::calCSCMatrix; - using autoware::qp_interface::CSC_Matrix; - - Eigen::MatrixXd rect1(1, 2); - rect1 << 0.0, 1.0; - - const CSC_Matrix rect_m1 = calCSCMatrix(rect1); - ASSERT_EQ(rect_m1.vals_.size(), size_t(1)); - EXPECT_EQ(rect_m1.vals_[0], 1.0); - ASSERT_EQ(rect_m1.row_idxs_.size(), size_t(1)); - EXPECT_EQ(rect_m1.row_idxs_[0], c_int(0)); - ASSERT_EQ(rect_m1.col_idxs_.size(), size_t(3)); // nb of columns + 1 - EXPECT_EQ(rect_m1.col_idxs_[0], c_int(0)); - EXPECT_EQ(rect_m1.col_idxs_[1], c_int(0)); - EXPECT_EQ(rect_m1.col_idxs_[2], c_int(1)); - - Eigen::MatrixXd rect2(2, 4); - rect2 << 1.0, 0.0, 3.0, 0.0, 0.0, 6.0, 7.0, 0.0; - - const CSC_Matrix rect_m2 = calCSCMatrix(rect2); - ASSERT_EQ(rect_m2.vals_.size(), size_t(4)); - EXPECT_EQ(rect_m2.vals_[0], 1.0); - EXPECT_EQ(rect_m2.vals_[1], 6.0); - EXPECT_EQ(rect_m2.vals_[2], 3.0); - EXPECT_EQ(rect_m2.vals_[3], 7.0); - ASSERT_EQ(rect_m2.row_idxs_.size(), size_t(4)); - EXPECT_EQ(rect_m2.row_idxs_[0], c_int(0)); - EXPECT_EQ(rect_m2.row_idxs_[1], c_int(1)); - EXPECT_EQ(rect_m2.row_idxs_[2], c_int(0)); - EXPECT_EQ(rect_m2.row_idxs_[3], c_int(1)); - ASSERT_EQ(rect_m2.col_idxs_.size(), size_t(5)); // nb of columns + 1 - EXPECT_EQ(rect_m2.col_idxs_[0], c_int(0)); - EXPECT_EQ(rect_m2.col_idxs_[1], c_int(1)); - EXPECT_EQ(rect_m2.col_idxs_[2], c_int(2)); - EXPECT_EQ(rect_m2.col_idxs_[3], c_int(4)); - EXPECT_EQ(rect_m2.col_idxs_[4], c_int(4)); - - // Example from http://netlib.org/linalg/html_templates/node92.html - Eigen::MatrixXd square2(6, 6); - square2 << 10.0, 0.0, 0.0, 0.0, -2.0, 0.0, 3.0, 9.0, 0.0, 0.0, 0.0, 3.0, 0.0, 7.0, 8.0, 7.0, 0.0, - 0.0, 3.0, 0.0, 8.0, 7.0, 5.0, 0.0, 0.0, 8.0, 0.0, 9.0, 9.0, 13.0, 0.0, 4.0, 0.0, 0.0, 2.0, -1.0; - - const CSC_Matrix square_m2 = calCSCMatrix(square2); - ASSERT_EQ(square_m2.vals_.size(), size_t(19)); - EXPECT_EQ(square_m2.vals_[0], 10.0); - EXPECT_EQ(square_m2.vals_[1], 3.0); - EXPECT_EQ(square_m2.vals_[2], 3.0); - EXPECT_EQ(square_m2.vals_[3], 9.0); - EXPECT_EQ(square_m2.vals_[4], 7.0); - EXPECT_EQ(square_m2.vals_[5], 8.0); - EXPECT_EQ(square_m2.vals_[6], 4.0); - EXPECT_EQ(square_m2.vals_[7], 8.0); - EXPECT_EQ(square_m2.vals_[8], 8.0); - EXPECT_EQ(square_m2.vals_[9], 7.0); - EXPECT_EQ(square_m2.vals_[10], 7.0); - EXPECT_EQ(square_m2.vals_[11], 9.0); - EXPECT_EQ(square_m2.vals_[12], -2.0); - EXPECT_EQ(square_m2.vals_[13], 5.0); - EXPECT_EQ(square_m2.vals_[14], 9.0); - EXPECT_EQ(square_m2.vals_[15], 2.0); - EXPECT_EQ(square_m2.vals_[16], 3.0); - EXPECT_EQ(square_m2.vals_[17], 13.0); - EXPECT_EQ(square_m2.vals_[18], -1.0); - ASSERT_EQ(square_m2.row_idxs_.size(), size_t(19)); - EXPECT_EQ(square_m2.row_idxs_[0], c_int(0)); - EXPECT_EQ(square_m2.row_idxs_[1], c_int(1)); - EXPECT_EQ(square_m2.row_idxs_[2], c_int(3)); - EXPECT_EQ(square_m2.row_idxs_[3], c_int(1)); - EXPECT_EQ(square_m2.row_idxs_[4], c_int(2)); - EXPECT_EQ(square_m2.row_idxs_[5], c_int(4)); - EXPECT_EQ(square_m2.row_idxs_[6], c_int(5)); - EXPECT_EQ(square_m2.row_idxs_[7], c_int(2)); - EXPECT_EQ(square_m2.row_idxs_[8], c_int(3)); - EXPECT_EQ(square_m2.row_idxs_[9], c_int(2)); - EXPECT_EQ(square_m2.row_idxs_[10], c_int(3)); - EXPECT_EQ(square_m2.row_idxs_[11], c_int(4)); - EXPECT_EQ(square_m2.row_idxs_[12], c_int(0)); - EXPECT_EQ(square_m2.row_idxs_[13], c_int(3)); - EXPECT_EQ(square_m2.row_idxs_[14], c_int(4)); - EXPECT_EQ(square_m2.row_idxs_[15], c_int(5)); - EXPECT_EQ(square_m2.row_idxs_[16], c_int(1)); - EXPECT_EQ(square_m2.row_idxs_[17], c_int(4)); - EXPECT_EQ(square_m2.row_idxs_[18], c_int(5)); - ASSERT_EQ(square_m2.col_idxs_.size(), size_t(7)); // nb of columns + 1 - EXPECT_EQ(square_m2.col_idxs_[0], c_int(0)); - EXPECT_EQ(square_m2.col_idxs_[1], c_int(3)); - EXPECT_EQ(square_m2.col_idxs_[2], c_int(7)); - EXPECT_EQ(square_m2.col_idxs_[3], c_int(9)); - EXPECT_EQ(square_m2.col_idxs_[4], c_int(12)); - EXPECT_EQ(square_m2.col_idxs_[5], c_int(16)); - EXPECT_EQ(square_m2.col_idxs_[6], c_int(19)); -} -TEST(TestCscMatrixConv, Trapezoidal) -{ - using autoware::qp_interface::calCSCMatrixTrapezoidal; - using autoware::qp_interface::CSC_Matrix; - - Eigen::MatrixXd square1(2, 2); - Eigen::MatrixXd square2(3, 3); - Eigen::MatrixXd rect1(1, 2); - square1 << 1.0, 2.0, 2.0, 4.0; - square2 << 0.0, 2.0, 0.0, 4.0, 5.0, 6.0, 0.0, 0.0, 0.0; - rect1 << 0.0, 1.0; - - const CSC_Matrix square_m1 = calCSCMatrixTrapezoidal(square1); - // Trapezoidal: skip the lower left triangle (2.0 in this example) - ASSERT_EQ(square_m1.vals_.size(), size_t(3)); - EXPECT_EQ(square_m1.vals_[0], 1.0); - EXPECT_EQ(square_m1.vals_[1], 2.0); - EXPECT_EQ(square_m1.vals_[2], 4.0); - ASSERT_EQ(square_m1.row_idxs_.size(), size_t(3)); - EXPECT_EQ(square_m1.row_idxs_[0], c_int(0)); - EXPECT_EQ(square_m1.row_idxs_[1], c_int(0)); - EXPECT_EQ(square_m1.row_idxs_[2], c_int(1)); - ASSERT_EQ(square_m1.col_idxs_.size(), size_t(3)); - EXPECT_EQ(square_m1.col_idxs_[0], c_int(0)); - EXPECT_EQ(square_m1.col_idxs_[1], c_int(1)); - EXPECT_EQ(square_m1.col_idxs_[2], c_int(3)); - - const CSC_Matrix square_m2 = calCSCMatrixTrapezoidal(square2); - ASSERT_EQ(square_m2.vals_.size(), size_t(3)); - EXPECT_EQ(square_m2.vals_[0], 2.0); - EXPECT_EQ(square_m2.vals_[1], 5.0); - EXPECT_EQ(square_m2.vals_[2], 6.0); - ASSERT_EQ(square_m2.row_idxs_.size(), size_t(3)); - EXPECT_EQ(square_m2.row_idxs_[0], c_int(0)); - EXPECT_EQ(square_m2.row_idxs_[1], c_int(1)); - EXPECT_EQ(square_m2.row_idxs_[2], c_int(1)); - ASSERT_EQ(square_m2.col_idxs_.size(), size_t(4)); - EXPECT_EQ(square_m2.col_idxs_[0], c_int(0)); - EXPECT_EQ(square_m2.col_idxs_[1], c_int(0)); - EXPECT_EQ(square_m2.col_idxs_[2], c_int(2)); - EXPECT_EQ(square_m2.col_idxs_[3], c_int(3)); - - try { - const CSC_Matrix rect_m1 = calCSCMatrixTrapezoidal(rect1); - FAIL() << "calCSCMatrixTrapezoidal should fail with non-square inputs"; - } catch (const std::invalid_argument & e) { - EXPECT_EQ(e.what(), std::string("Matrix must be square (n, n)")); - } -} -TEST(TestCscMatrixConv, Print) -{ - using autoware::qp_interface::calCSCMatrix; - using autoware::qp_interface::calCSCMatrixTrapezoidal; - using autoware::qp_interface::CSC_Matrix; - using autoware::qp_interface::printCSCMatrix; - Eigen::MatrixXd square1(2, 2); - Eigen::MatrixXd rect1(1, 2); - square1 << 1.0, 2.0, 2.0, 4.0; - rect1 << 0.0, 1.0; - const CSC_Matrix square_m1 = calCSCMatrixTrapezoidal(square1); - const CSC_Matrix rect_m1 = calCSCMatrix(rect1); - printCSCMatrix(square_m1); - printCSCMatrix(rect_m1); -} diff --git a/common/autoware_qp_interface/test/test_osqp_interface.cpp b/common/autoware_qp_interface/test/test_osqp_interface.cpp deleted file mode 100644 index f97cc2888afa0..0000000000000 --- a/common/autoware_qp_interface/test/test_osqp_interface.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/qp_interface/osqp_interface.hpp" -#include "gtest/gtest.h" - -#include - -#include -#include -#include -#include - -namespace -{ -// Problem taken from https://github.com/osqp/osqp/blob/master/tests/basic_qp/generate_problem.py -// -// min 1/2 * x' * P * x + q' * x -// s.t. lb <= A * x <= ub -// -// P = [4, 1], q = [1], A = [1, 1], lb = [ 1], ub = [1.0] -// [1, 2] [1] [1, 0] [ 0] [0.7] -// [0, 1] [ 0] [0.7] -// [0, 1] [-inf] [inf] -// -// The optimal solution is -// x = [0.3, 0.7]' -// y = [-2.9, 0.0, 0.2, 0.0]` -// obj = 1.88 - -TEST(TestOsqpInterface, BasicQp) -{ - using autoware::qp_interface::calCSCMatrix; - using autoware::qp_interface::calCSCMatrixTrapezoidal; - using autoware::qp_interface::CSC_Matrix; - - auto check_result = - [](const auto & solution, const std::string & status, const int polish_status) { - EXPECT_EQ(status, "OSQP_SOLVED"); - EXPECT_EQ(polish_status, 1); - - static const auto ep = 1.0e-8; - - ASSERT_EQ(solution.size(), size_t(2)); - EXPECT_NEAR(solution[0], 0.3, ep); - EXPECT_NEAR(solution[1], 0.7, ep); - }; - - const Eigen::MatrixXd P = (Eigen::MatrixXd(2, 2) << 4, 1, 1, 2).finished(); - const Eigen::MatrixXd A = (Eigen::MatrixXd(4, 2) << 1, 1, 1, 0, 0, 1, 0, 1).finished(); - const std::vector q = {1.0, 1.0}; - const std::vector l = {1.0, 0.0, 0.0, -autoware::qp_interface::OSQP_INF}; - const std::vector u = {1.0, 0.7, 0.7, autoware::qp_interface::OSQP_INF}; - - { - // Define problem during optimization - autoware::qp_interface::OSQPInterface osqp(false, 4000, 1e-6); - const auto solution = osqp.QPInterface::optimize(P, A, q, l, u); - const auto status = osqp.getStatus(); - const auto polish_status = osqp.getPolishStatus(); - check_result(solution, status, polish_status); - } - - { - // Define problem during initialization - autoware::qp_interface::OSQPInterface osqp(false, 4000, 1e-6); - const auto solution = osqp.QPInterface::optimize(P, A, q, l, u); - const auto status = osqp.getStatus(); - const auto polish_status = osqp.getPolishStatus(); - check_result(solution, status, polish_status); - } - - { - std::tuple, std::vector, int, int, int> result; - // Dummy initial problem - Eigen::MatrixXd P_ini = Eigen::MatrixXd::Zero(2, 2); - Eigen::MatrixXd A_ini = Eigen::MatrixXd::Zero(4, 2); - std::vector q_ini(2, 0.0); - std::vector l_ini(4, 0.0); - std::vector u_ini(4, 0.0); - autoware::qp_interface::OSQPInterface osqp(false, 4000, 1e-6); - osqp.QPInterface::optimize(P_ini, A_ini, q_ini, l_ini, u_ini); - } - - { - // Define problem during initialization with csc matrix - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - autoware::qp_interface::OSQPInterface osqp(false, 4000, 1e-6); - - const auto solution = osqp.optimize(P_csc, A_csc, q, l, u); - const auto status = osqp.getStatus(); - const auto polish_status = osqp.getPolishStatus(); - check_result(solution, status, polish_status); - } - - { - std::tuple, std::vector, int, int, int> result; - // Dummy initial problem with csc matrix - CSC_Matrix P_ini_csc = calCSCMatrixTrapezoidal(Eigen::MatrixXd::Zero(2, 2)); - CSC_Matrix A_ini_csc = calCSCMatrix(Eigen::MatrixXd::Zero(4, 2)); - std::vector q_ini(2, 0.0); - std::vector l_ini(4, 0.0); - std::vector u_ini(4, 0.0); - autoware::qp_interface::OSQPInterface osqp(false, 4000, 1e-6); - osqp.optimize(P_ini_csc, A_ini_csc, q_ini, l_ini, u_ini); - - // Redefine problem before optimization - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - - const auto solution = osqp.optimize(P_csc, A_csc, q, l, u); - const auto status = osqp.getStatus(); - const auto polish_status = osqp.getPolishStatus(); - check_result(solution, status, polish_status); - } - - // add warm startup - { - // Dummy initial problem with csc matrix - CSC_Matrix P_ini_csc = calCSCMatrixTrapezoidal(Eigen::MatrixXd::Zero(2, 2)); - CSC_Matrix A_ini_csc = calCSCMatrix(Eigen::MatrixXd::Zero(4, 2)); - std::vector q_ini(2, 0.0); - std::vector l_ini(4, 0.0); - std::vector u_ini(4, 0.0); - autoware::qp_interface::OSQPInterface osqp(true, 4000, 1e-6); // enable warm start - osqp.optimize(P_ini_csc, A_ini_csc, q_ini, l_ini, u_ini); - - // Redefine problem before optimization - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - { - const auto solution = osqp.optimize(P_csc, A_csc, q, l, u); - const auto status = osqp.getStatus(); - const auto polish_status = osqp.getPolishStatus(); - check_result(solution, status, polish_status); - - osqp.updateCheckTermination(1); - const auto primal_val = solution; - const auto dual_val = osqp.getDualSolution(); - for (size_t i = 0; i < primal_val.size(); ++i) { - std::cerr << primal_val.at(i) << std::endl; - } - osqp.setWarmStart(primal_val, dual_val); - } - - { - const auto solution = osqp.optimize(P_csc, A_csc, q, l, u); - const auto status = osqp.getStatus(); - const auto polish_status = osqp.getPolishStatus(); - check_result(solution, status, polish_status); - } - - // NOTE: This should be true, but currently optimize function reset the workspace, which - // disables warm start. - // EXPECT_EQ(osqp.getTakenIter(), 1); - } -} -} // namespace diff --git a/common/autoware_qp_interface/test/test_proxqp_interface.cpp b/common/autoware_qp_interface/test/test_proxqp_interface.cpp deleted file mode 100644 index e47af10c7aabd..0000000000000 --- a/common/autoware_qp_interface/test/test_proxqp_interface.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2023 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/qp_interface/proxqp_interface.hpp" -#include "gtest/gtest.h" - -#include - -#include -#include -#include -#include - -namespace -{ -// Problem taken from -// https://github.com/proxqp/proxqp/blob/master/tests/basic_qp/generate_problem.py -// -// min 1/2 * x' * P * x + q' * x -// s.t. lb <= A * x <= ub -// -// P = [4, 1], q = [1], A = [1, 1], lb = [ 1], ub = [1.0] -// [1, 2] [1] [1, 0] [ 0] [0.7] -// [0, 1] [ 0] [0.7] -// [0, 1] [-inf] [inf] -// -// The optimal solution is -// x = [0.3, 0.7]' -// y = [-2.9, 0.0, 0.2, 0.0]` -// obj = 1.88 - -TEST(TestProxqpInterface, BasicQp) -{ - auto check_result = [](const auto & solution, const std::string & status) { - EXPECT_EQ(status, "PROXQP_SOLVED"); - - static const auto ep = 1.0e-8; - ASSERT_EQ(solution.size(), size_t(2)); - EXPECT_NEAR(solution[0], 0.3, ep); - EXPECT_NEAR(solution[1], 0.7, ep); - }; - - const Eigen::MatrixXd P = (Eigen::MatrixXd(2, 2) << 4, 1, 1, 2).finished(); - const Eigen::MatrixXd A = (Eigen::MatrixXd(4, 2) << 1, 1, 1, 0, 0, 1, 0, 1).finished(); - const std::vector q = {1.0, 1.0}; - const std::vector l = {1.0, 0.0, 0.0, -std::numeric_limits::max()}; - const std::vector u = {1.0, 0.7, 0.7, std::numeric_limits::max()}; - - { - // Define problem during optimization - autoware::qp_interface::ProxQPInterface proxqp(false, 4000, 1e-9, 1e-9, false); - const auto solution = proxqp.QPInterface::optimize(P, A, q, l, u); - const auto status = proxqp.getStatus(); - check_result(solution, status); - } - - { - // Define problem during optimization with warm start - autoware::qp_interface::ProxQPInterface proxqp(true, 4000, 1e-9, 1e-9, false); - { - const auto solution = proxqp.QPInterface::optimize(P, A, q, l, u); - const auto status = proxqp.getStatus(); - check_result(solution, status); - EXPECT_NE(proxqp.getIterationNumber(), 1); - } - { - const auto solution = proxqp.QPInterface::optimize(P, A, q, l, u); - const auto status = proxqp.getStatus(); - check_result(solution, status); - EXPECT_EQ(proxqp.getIterationNumber(), 0); - } - } -} -} // namespace From 997146c94c4f5eaa0547206981b1566879c0a266 Mon Sep 17 00:00:00 2001 From: NorahXiong <103234047+NorahXiong@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:11:09 +0800 Subject: [PATCH 20/61] feat(autoware_osqp_interface): porting autoware_osqp_interface package to autoware.core (#9890) Signed-off-by: NorahXiong --- common/autoware_osqp_interface/CHANGELOG.rst | 51 -- common/autoware_osqp_interface/CMakeLists.txt | 58 --- .../design/osqp_interface-design.md | 70 --- .../osqp_interface/csc_matrix_conv.hpp | 47 -- .../osqp_interface/osqp_interface.hpp | 194 -------- .../osqp_interface/visibility_control.hpp | 37 -- common/autoware_osqp_interface/package.xml | 29 -- .../src/csc_matrix_conv.cpp | 135 ------ .../src/osqp_interface.cpp | 435 ------------------ .../test/test_csc_matrix_conv.cpp | 181 -------- .../test/test_osqp_interface.cpp | 164 ------- 11 files changed, 1401 deletions(-) delete mode 100644 common/autoware_osqp_interface/CHANGELOG.rst delete mode 100644 common/autoware_osqp_interface/CMakeLists.txt delete mode 100644 common/autoware_osqp_interface/design/osqp_interface-design.md delete mode 100644 common/autoware_osqp_interface/include/autoware/osqp_interface/csc_matrix_conv.hpp delete mode 100644 common/autoware_osqp_interface/include/autoware/osqp_interface/osqp_interface.hpp delete mode 100644 common/autoware_osqp_interface/include/autoware/osqp_interface/visibility_control.hpp delete mode 100644 common/autoware_osqp_interface/package.xml delete mode 100644 common/autoware_osqp_interface/src/csc_matrix_conv.cpp delete mode 100644 common/autoware_osqp_interface/src/osqp_interface.cpp delete mode 100644 common/autoware_osqp_interface/test/test_csc_matrix_conv.cpp delete mode 100644 common/autoware_osqp_interface/test/test_osqp_interface.cpp diff --git a/common/autoware_osqp_interface/CHANGELOG.rst b/common/autoware_osqp_interface/CHANGELOG.rst deleted file mode 100644 index d400b77f4bf61..0000000000000 --- a/common/autoware_osqp_interface/CHANGELOG.rst +++ /dev/null @@ -1,51 +0,0 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Changelog for package autoware_osqp_interface -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -0.40.0 (2024-12-12) -------------------- -* Merge branch 'main' into release-0.40.0 -* Revert "chore(package.xml): bump version to 0.39.0 (`#9587 `_)" - This reverts commit c9f0f2688c57b0f657f5c1f28f036a970682e7f5. -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* chore(package.xml): bump version to 0.39.0 (`#9587 `_) - * chore(package.xml): bump version to 0.39.0 - * fix: fix ticket links in CHANGELOG.rst - * fix: remove unnecessary diff - --------- - Co-authored-by: Yutaka Kondo -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* fix(cpplint): include what you use - common (`#9564 `_) -* fix(autoware_osqp_interface): fix clang-tidy errors (`#9440 `_) -* 0.39.0 -* update changelog -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* Contributors: Esteve Fernandez, Fumiya Watanabe, M. Fatih Cırıt, Ryohsuke Mitsudome, Ryuta Kambe, Yutaka Kondo - -0.39.0 (2024-11-25) -------------------- -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* Contributors: Esteve Fernandez, Yutaka Kondo - -0.38.0 (2024-11-08) -------------------- -* unify package.xml version to 0.37.0 -* refactor(osqp_interface): added autoware prefix to osqp_interface (`#8958 `_) -* Contributors: Esteve Fernandez, Yutaka Kondo - -0.26.0 (2024-04-03) -------------------- diff --git a/common/autoware_osqp_interface/CMakeLists.txt b/common/autoware_osqp_interface/CMakeLists.txt deleted file mode 100644 index b770af659e52a..0000000000000 --- a/common/autoware_osqp_interface/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(autoware_osqp_interface) - -find_package(autoware_cmake REQUIRED) -autoware_package() - -find_package(Eigen3 REQUIRED) - -# after find_package(osqp_vendor) in ament_auto_find_build_dependencies -find_package(osqp REQUIRED) -get_target_property(OSQP_INCLUDE_SUB_DIR osqp::osqp INTERFACE_INCLUDE_DIRECTORIES) -get_filename_component(OSQP_INCLUDE_DIR ${OSQP_INCLUDE_SUB_DIR} PATH) - -set(OSQP_INTERFACE_LIB_SRC - src/csc_matrix_conv.cpp - src/osqp_interface.cpp -) - -set(OSQP_INTERFACE_LIB_HEADERS - include/autoware/osqp_interface/csc_matrix_conv.hpp - include/autoware/osqp_interface/osqp_interface.hpp - include/autoware/osqp_interface/visibility_control.hpp -) - -ament_auto_add_library(${PROJECT_NAME} SHARED - ${OSQP_INTERFACE_LIB_SRC} - ${OSQP_INTERFACE_LIB_HEADERS} -) -target_compile_options(${PROJECT_NAME} PRIVATE -Wno-error=old-style-cast) - -target_include_directories(${PROJECT_NAME} - SYSTEM PUBLIC - "${OSQP_INCLUDE_DIR}" - "${EIGEN3_INCLUDE_DIR}" -) - -ament_target_dependencies(${PROJECT_NAME} - Eigen3 - osqp_vendor -) - -# crucial so downstream package builds because autoware_osqp_interface exposes osqp.hpp -ament_export_include_directories("${OSQP_INCLUDE_DIR}") -# crucial so the linking order is correct in a downstream package: libosqp_interface.a should come before libosqp.a -ament_export_libraries(osqp::osqp) - -if(BUILD_TESTING) - set(TEST_SOURCES - test/test_osqp_interface.cpp - test/test_csc_matrix_conv.cpp - ) - set(TEST_OSQP_INTERFACE_EXE test_osqp_interface) - ament_add_ros_isolated_gtest(${TEST_OSQP_INTERFACE_EXE} ${TEST_SOURCES}) - target_link_libraries(${TEST_OSQP_INTERFACE_EXE} ${PROJECT_NAME}) -endif() - -ament_auto_package(INSTALL_TO_SHARE -) diff --git a/common/autoware_osqp_interface/design/osqp_interface-design.md b/common/autoware_osqp_interface/design/osqp_interface-design.md deleted file mode 100644 index 887a4b4d9af3f..0000000000000 --- a/common/autoware_osqp_interface/design/osqp_interface-design.md +++ /dev/null @@ -1,70 +0,0 @@ -# Interface for the OSQP library - -This is the design document for the `autoware_osqp_interface` package. - -## Purpose / Use cases - - - - -This packages provides a C++ interface for the [OSQP library](https://osqp.org/docs/solver/index.html). - -## Design - - - - -The class `OSQPInterface` takes a problem formulation as Eigen matrices and vectors, converts these objects into -C-style Compressed-Column-Sparse matrices and dynamic arrays, loads the data into the OSQP workspace dataholder, and runs the optimizer. - -## Inputs / Outputs / API - - - - -The interface can be used in several ways: - -1. Initialize the interface WITHOUT data. Load the problem formulation at the optimization call. - - ```cpp - osqp_interface = OSQPInterface(); - osqp_interface.optimize(P, A, q, l, u); - ``` - -2. Initialize the interface WITH data. - - ```cpp - osqp_interface = OSQPInterface(P, A, q, l, u); - osqp_interface.optimize(); - ``` - -3. WARM START OPTIMIZATION by modifying the problem formulation between optimization runs. - - ```cpp - osqp_interface = OSQPInterface(P, A, q, l, u); - osqp_interface.optimize(); - osqp.initializeProblem(P_new, A_new, q_new, l_new, u_new); - osqp_interface.optimize(); - ``` - - The optimization results are returned as a vector by the optimization function. - - ```cpp - std::tuple, std::vector> result = osqp_interface.optimize(); - std::vector param = std::get<0>(result); - double x_0 = param[0]; - double x_1 = param[1]; - ``` - -## References / External links - - - -- OSQP library: - -## Related issues - - diff --git a/common/autoware_osqp_interface/include/autoware/osqp_interface/csc_matrix_conv.hpp b/common/autoware_osqp_interface/include/autoware/osqp_interface/csc_matrix_conv.hpp deleted file mode 100644 index 8c21553152d70..0000000000000 --- a/common/autoware_osqp_interface/include/autoware/osqp_interface/csc_matrix_conv.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2021 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__OSQP_INTERFACE__CSC_MATRIX_CONV_HPP_ -#define AUTOWARE__OSQP_INTERFACE__CSC_MATRIX_CONV_HPP_ - -#include "autoware/osqp_interface/visibility_control.hpp" -#include "osqp/glob_opts.h" // for 'c_int' type ('long' or 'long long') - -#include - -#include - -namespace autoware::osqp_interface -{ -/// \brief Compressed-Column-Sparse Matrix -struct OSQP_INTERFACE_PUBLIC CSC_Matrix -{ - /// Vector of non-zero values. Ex: [4,1,1,2] - std::vector m_vals; - /// Vector of row index corresponding to values. Ex: [0, 1, 0, 1] (Eigen: 'inner') - std::vector m_row_idxs; - /// Vector of 'val' indices where each column starts. Ex: [0, 2, 4] (Eigen: 'outer') - std::vector m_col_idxs; -}; - -/// \brief Calculate CSC matrix from Eigen matrix -OSQP_INTERFACE_PUBLIC CSC_Matrix calCSCMatrix(const Eigen::MatrixXd & mat); -/// \brief Calculate upper trapezoidal CSC matrix from square Eigen matrix -OSQP_INTERFACE_PUBLIC CSC_Matrix calCSCMatrixTrapezoidal(const Eigen::MatrixXd & mat); -/// \brief Print the given CSC matrix to the standard output -OSQP_INTERFACE_PUBLIC void printCSCMatrix(const CSC_Matrix & csc_mat); - -} // namespace autoware::osqp_interface - -#endif // AUTOWARE__OSQP_INTERFACE__CSC_MATRIX_CONV_HPP_ diff --git a/common/autoware_osqp_interface/include/autoware/osqp_interface/osqp_interface.hpp b/common/autoware_osqp_interface/include/autoware/osqp_interface/osqp_interface.hpp deleted file mode 100644 index ff3013bd61514..0000000000000 --- a/common/autoware_osqp_interface/include/autoware/osqp_interface/osqp_interface.hpp +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2021 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__OSQP_INTERFACE__OSQP_INTERFACE_HPP_ -#define AUTOWARE__OSQP_INTERFACE__OSQP_INTERFACE_HPP_ - -#include "autoware/osqp_interface/csc_matrix_conv.hpp" -#include "autoware/osqp_interface/visibility_control.hpp" -#include "osqp/osqp.h" - -#include -#include - -#include -#include -#include -#include -#include - -namespace autoware::osqp_interface -{ -constexpr c_float INF = 1e30; - -/** - * Implementation of a native C++ interface for the OSQP solver. - * - */ -class OSQP_INTERFACE_PUBLIC OSQPInterface -{ -private: - std::unique_ptr> m_work; - std::unique_ptr m_settings; - std::unique_ptr m_data; - // store last work info since work is cleaned up at every execution to prevent memory leak. - OSQPInfo m_latest_work_info; - // Number of parameters to optimize - int64_t m_param_n; - // Flag to check if the current work exists - bool m_work_initialized = false; - // Exitflag - int64_t m_exitflag; - - // Runs the solver on the stored problem. - std::tuple, std::vector, int64_t, int64_t, int64_t> solve(); - - static void OSQPWorkspaceDeleter(OSQPWorkspace * ptr) noexcept; - -public: - /// \brief Constructor without problem formulation - explicit OSQPInterface( - const c_float eps_abs = std::numeric_limits::epsilon(), const bool polish = true); - /// \brief Constructor with problem setup - /// \param P: (n,n) matrix defining relations between parameters. - /// \param A: (m,n) matrix defining parameter constraints relative to the lower and upper bound. - /// \param q: (n) vector defining the linear cost of the problem. - /// \param l: (m) vector defining the lower bound problem constraint. - /// \param u: (m) vector defining the upper bound problem constraint. - /// \param eps_abs: Absolute convergence tolerance. - OSQPInterface( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u, const c_float eps_abs); - OSQPInterface( - const CSC_Matrix & P, const CSC_Matrix & A, const std::vector & q, - const std::vector & l, const std::vector & u, const c_float eps_abs); - ~OSQPInterface(); - - /**************** - * OPTIMIZATION - ****************/ - /// \brief Solves the stored convex quadratic program (QP) problem using the OSQP solver. - // - /// \return The function returns a tuple containing the solution as two float vectors. - /// \return The first element of the tuple contains the 'primal' solution. - /// \return The second element contains the 'lagrange multiplier' solution. - /// \return The third element contains an integer with solver polish status information. - - /// \details How to use: - /// \details 1. Generate the Eigen matrices P, A and vectors q, l, u according to the problem. - /// \details 2. Initialize the interface and set up the problem. - /// \details osqp_interface = OSQPInterface(P, A, q, l, u, 1e-6); - /// \details 3. Call the optimization function. - /// \details std::tuple, std::vector> result; - /// \details result = osqp_interface.optimize(); - /// \details 4. Access the optimized parameters. - /// \details std::vector param = std::get<0>(result); - /// \details double x_0 = param[0]; - /// \details double x_1 = param[1]; - std::tuple, std::vector, int64_t, int64_t, int64_t> optimize(); - - /// \brief Solves convex quadratic programs (QPs) using the OSQP solver. - /// \return The function returns a tuple containing the solution as two float vectors. - /// \return The first element of the tuple contains the 'primal' solution. - /// \return The second element contains the 'lagrange multiplier' solution. - /// \return The third element contains an integer with solver polish status information. - /// \details How to use: - /// \details 1. Generate the Eigen matrices P, A and vectors q, l, u according to the problem. - /// \details 2. Initialize the interface. - /// \details osqp_interface = OSQPInterface(1e-6); - /// \details 3. Call the optimization function with the problem formulation. - /// \details std::tuple, std::vector> result; - /// \details result = osqp_interface.optimize(P, A, q, l, u, 1e-6); - /// \details 4. Access the optimized parameters. - /// \details std::vector param = std::get<0>(result); - /// \details double x_0 = param[0]; - /// \details double x_1 = param[1]; - std::tuple, std::vector, int64_t, int64_t, int64_t> optimize( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u); - - /// \brief Converts the input data and sets up the workspace object. - /// \param P (n,n) matrix defining relations between parameters. - /// \param A (m,n) matrix defining parameter constraints relative to the lower and upper bound. - /// \param q (n) vector defining the linear cost of the problem. - /// \param l (m) vector defining the lower bound problem constraint. - /// \param u (m) vector defining the upper bound problem constraint. - int64_t initializeProblem( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u); - int64_t initializeProblem( - CSC_Matrix P, CSC_Matrix A, const std::vector & q, const std::vector & l, - const std::vector & u); - - // Setter functions for warm start - bool setWarmStart( - const std::vector & primal_variables, const std::vector & dual_variables); - bool setPrimalVariables(const std::vector & primal_variables); - bool setDualVariables(const std::vector & dual_variables); - - // Updates problem parameters while keeping solution in memory. - // - // Args: - // P_new: (n,n) matrix defining relations between parameters. - // A_new: (m,n) matrix defining parameter constraints relative to the lower and upper bound. - // q_new: (n) vector defining the linear cost of the problem. - // l_new: (m) vector defining the lower bound problem constraint. - // u_new: (m) vector defining the upper bound problem constraint. - void updateP(const Eigen::MatrixXd & P_new); - void updateCscP(const CSC_Matrix & P_csc); - void updateA(const Eigen::MatrixXd & A_new); - void updateCscA(const CSC_Matrix & A_csc); - void updateQ(const std::vector & q_new); - void updateL(const std::vector & l_new); - void updateU(const std::vector & u_new); - void updateBounds(const std::vector & l_new, const std::vector & u_new); - void updateEpsAbs(const double eps_abs); - void updateEpsRel(const double eps_rel); - void updateMaxIter(const int iter); - void updateVerbose(const bool verbose); - void updateRhoInterval(const int rho_interval); - void updateRho(const double rho); - void updateAlpha(const double alpha); - void updateScaling(const int scaling); - void updatePolish(const bool polish); - void updatePolishRefinementIteration(const int polish_refine_iter); - void updateCheckTermination(const int check_termination); - - /// \brief Get the number of iteration taken to solve the problem - inline int64_t getTakenIter() const { return static_cast(m_latest_work_info.iter); } - /// \brief Get the status message for the latest problem solved - inline std::string getStatusMessage() const - { - return static_cast(m_latest_work_info.status); - } - /// \brief Get the status value for the latest problem solved - inline int64_t getStatus() const { return static_cast(m_latest_work_info.status_val); } - /// \brief Get the status polish for the latest problem solved - inline int64_t getStatusPolish() const - { - return static_cast(m_latest_work_info.status_polish); - } - /// \brief Get the runtime of the latest problem solved - inline double getRunTime() const { return m_latest_work_info.run_time; } - /// \brief Get the objective value the latest problem solved - inline double getObjVal() const { return m_latest_work_info.obj_val; } - /// \brief Returns flag asserting interface condition (Healthy condition: 0). - inline int64_t getExitFlag() const { return m_exitflag; } - - void logUnsolvedStatus(const std::string & prefix_message = "") const; -}; - -} // namespace autoware::osqp_interface - -#endif // AUTOWARE__OSQP_INTERFACE__OSQP_INTERFACE_HPP_ diff --git a/common/autoware_osqp_interface/include/autoware/osqp_interface/visibility_control.hpp b/common/autoware_osqp_interface/include/autoware/osqp_interface/visibility_control.hpp deleted file mode 100644 index a6cdaa8a0a74e..0000000000000 --- a/common/autoware_osqp_interface/include/autoware/osqp_interface/visibility_control.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2021 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__OSQP_INTERFACE__VISIBILITY_CONTROL_HPP_ -#define AUTOWARE__OSQP_INTERFACE__VISIBILITY_CONTROL_HPP_ - -//////////////////////////////////////////////////////////////////////////////// -#if defined(__WIN32) -#if defined(OSQP_INTERFACE_BUILDING_DLL) || defined(OSQP_INTERFACE_EXPORTS) -#define OSQP_INTERFACE_PUBLIC __declspec(dllexport) -#define OSQP_INTERFACE_LOCAL -#else // defined(OSQP_INTERFACE_BUILDING_DLL) || defined(OSQP_INTERFACE_EXPORTS) -#define OSQP_INTERFACE_PUBLIC __declspec(dllimport) -#define OSQP_INTERFACE_LOCAL -#endif // defined(OSQP_INTERFACE_BUILDING_DLL) || defined(OSQP_INTERFACE_EXPORTS) -#elif defined(__linux__) -#define OSQP_INTERFACE_PUBLIC __attribute__((visibility("default"))) -#define OSQP_INTERFACE_LOCAL __attribute__((visibility("hidden"))) -#elif defined(__APPLE__) -#define OSQP_INTERFACE_PUBLIC __attribute__((visibility("default"))) -#define OSQP_INTERFACE_LOCAL __attribute__((visibility("hidden"))) -#else -#error "Unsupported Build Configuration" -#endif - -#endif // AUTOWARE__OSQP_INTERFACE__VISIBILITY_CONTROL_HPP_ diff --git a/common/autoware_osqp_interface/package.xml b/common/autoware_osqp_interface/package.xml deleted file mode 100644 index 92a2afeccc4e0..0000000000000 --- a/common/autoware_osqp_interface/package.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - autoware_osqp_interface - 0.40.0 - Interface for the OSQP solver - Maxime CLEMENT - Takayuki Murooka - Fumiya Watanabe - Satoshi Ota - Apache 2.0 - - ament_cmake_auto - autoware_cmake - - eigen - osqp_vendor - rclcpp - rclcpp_components - - ament_cmake_ros - ament_lint_auto - autoware_lint_common - eigen - - - ament_cmake - - diff --git a/common/autoware_osqp_interface/src/csc_matrix_conv.cpp b/common/autoware_osqp_interface/src/csc_matrix_conv.cpp deleted file mode 100644 index c6e1a0a42d938..0000000000000 --- a/common/autoware_osqp_interface/src/csc_matrix_conv.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2021 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/osqp_interface/csc_matrix_conv.hpp" - -#include -#include - -#include -#include -#include - -namespace autoware::osqp_interface -{ -CSC_Matrix calCSCMatrix(const Eigen::MatrixXd & mat) -{ - const size_t elem = static_cast(mat.nonZeros()); - const Eigen::Index rows = mat.rows(); - const Eigen::Index cols = mat.cols(); - - std::vector vals; - vals.reserve(elem); - std::vector row_idxs; - row_idxs.reserve(elem); - std::vector col_idxs; - col_idxs.reserve(elem); - - // Construct CSC matrix arrays - c_float val; - c_int elem_count = 0; - - col_idxs.push_back(0); - - for (Eigen::Index j = 0; j < cols; j++) { // col iteration - for (Eigen::Index i = 0; i < rows; i++) { // row iteration - // Get values of nonzero elements - val = mat(i, j); - if (std::fabs(val) < 1e-9) { - continue; - } - elem_count += 1; - - // Store values - vals.push_back(val); - row_idxs.push_back(i); - } - - col_idxs.push_back(elem_count); - } - - CSC_Matrix csc_matrix = {vals, row_idxs, col_idxs}; - - return csc_matrix; -} - -CSC_Matrix calCSCMatrixTrapezoidal(const Eigen::MatrixXd & mat) -{ - const size_t elem = static_cast(mat.nonZeros()); - const Eigen::Index rows = mat.rows(); - const Eigen::Index cols = mat.cols(); - - if (rows != cols) { - throw std::invalid_argument("Matrix must be square (n, n)"); - } - - std::vector vals; - vals.reserve(elem); - std::vector row_idxs; - row_idxs.reserve(elem); - std::vector col_idxs; - col_idxs.reserve(elem); - - // Construct CSC matrix arrays - c_float val; - Eigen::Index trap_last_idx = 0; - c_int elem_count = 0; - - col_idxs.push_back(0); - - for (Eigen::Index j = 0; j < cols; j++) { // col iteration - for (Eigen::Index i = 0; i <= trap_last_idx; i++) { // row iteration - // Get values of nonzero elements - val = mat(i, j); - if (std::fabs(val) < 1e-9) { - continue; - } - elem_count += 1; - - // Store values - vals.push_back(val); - row_idxs.push_back(i); - } - - col_idxs.push_back(elem_count); - trap_last_idx += 1; - } - - CSC_Matrix csc_matrix = {vals, row_idxs, col_idxs}; - - return csc_matrix; -} - -void printCSCMatrix(const CSC_Matrix & csc_mat) -{ - std::cout << "["; - for (const c_float & val : csc_mat.m_vals) { - std::cout << val << ", "; - } - std::cout << "]\n"; - - std::cout << "["; - for (const c_int & row : csc_mat.m_row_idxs) { - std::cout << row << ", "; - } - std::cout << "]\n"; - - std::cout << "["; - for (const c_int & col : csc_mat.m_col_idxs) { - std::cout << col << ", "; - } - std::cout << "]\n"; -} - -} // namespace autoware::osqp_interface diff --git a/common/autoware_osqp_interface/src/osqp_interface.cpp b/common/autoware_osqp_interface/src/osqp_interface.cpp deleted file mode 100644 index ceeae626222ca..0000000000000 --- a/common/autoware_osqp_interface/src/osqp_interface.cpp +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2021 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/osqp_interface/osqp_interface.hpp" - -#include "autoware/osqp_interface/csc_matrix_conv.hpp" -#include "osqp/osqp.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace autoware::osqp_interface -{ -OSQPInterface::OSQPInterface(const c_float eps_abs, const bool polish) -: m_work{nullptr, OSQPWorkspaceDeleter} -{ - m_settings = std::make_unique(); - m_data = std::make_unique(); - - if (m_settings) { - osqp_set_default_settings(m_settings.get()); - m_settings->alpha = 1.6; // Change alpha parameter - m_settings->eps_rel = 1.0E-4; - m_settings->eps_abs = eps_abs; - m_settings->eps_prim_inf = 1.0E-4; - m_settings->eps_dual_inf = 1.0E-4; - m_settings->warm_start = true; - m_settings->max_iter = 4000; - m_settings->verbose = false; - m_settings->polish = polish; - } - m_exitflag = 0; -} - -OSQPInterface::OSQPInterface( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u, const c_float eps_abs) -: OSQPInterface(eps_abs) -{ - initializeProblem(P, A, q, l, u); -} - -OSQPInterface::OSQPInterface( - const CSC_Matrix & P, const CSC_Matrix & A, const std::vector & q, - const std::vector & l, const std::vector & u, const c_float eps_abs) -: OSQPInterface(eps_abs) -{ - initializeProblem(P, A, q, l, u); -} - -OSQPInterface::~OSQPInterface() -{ - if (m_data->P) free(m_data->P); - if (m_data->A) free(m_data->A); -} - -void OSQPInterface::OSQPWorkspaceDeleter(OSQPWorkspace * ptr) noexcept -{ - if (ptr != nullptr) { - osqp_cleanup(ptr); - } -} - -void OSQPInterface::updateP(const Eigen::MatrixXd & P_new) -{ - /* - // Transform 'P' into an 'upper trapezoidal matrix' - Eigen::MatrixXd P_trap = P_new.triangularView(); - // Transform 'P' into a sparse matrix and extract data as dynamic arrays - Eigen::SparseMatrix P_sparse = P_trap.sparseView(); - double *P_val_ptr = P_sparse.valuePtr(); - // Convert dynamic 'int' arrays to 'c_int' arrays (OSQP input type) - c_int P_elem_N = P_sparse.nonZeros(); - */ - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P_new); - osqp_update_P( - m_work.get(), P_csc.m_vals.data(), OSQP_NULL, static_cast(P_csc.m_vals.size())); -} - -void OSQPInterface::updateCscP(const CSC_Matrix & P_csc) -{ - osqp_update_P( - m_work.get(), P_csc.m_vals.data(), OSQP_NULL, static_cast(P_csc.m_vals.size())); -} - -void OSQPInterface::updateA(const Eigen::MatrixXd & A_new) -{ - /* - // Transform 'A' into a sparse matrix and extract data as dynamic arrays - Eigen::SparseMatrix A_sparse = A_new.sparseView(); - double *A_val_ptr = A_sparse.valuePtr(); - // Convert dynamic 'int' arrays to 'c_int' arrays (OSQP input type) - c_int A_elem_N = A_sparse.nonZeros(); - */ - CSC_Matrix A_csc = calCSCMatrix(A_new); - osqp_update_A( - m_work.get(), A_csc.m_vals.data(), OSQP_NULL, static_cast(A_csc.m_vals.size())); - return; -} - -void OSQPInterface::updateCscA(const CSC_Matrix & A_csc) -{ - osqp_update_A( - m_work.get(), A_csc.m_vals.data(), OSQP_NULL, static_cast(A_csc.m_vals.size())); -} - -void OSQPInterface::updateQ(const std::vector & q_new) -{ - std::vector q_tmp(q_new.begin(), q_new.end()); - double * q_dyn = q_tmp.data(); - osqp_update_lin_cost(m_work.get(), q_dyn); -} - -void OSQPInterface::updateL(const std::vector & l_new) -{ - std::vector l_tmp(l_new.begin(), l_new.end()); - double * l_dyn = l_tmp.data(); - osqp_update_lower_bound(m_work.get(), l_dyn); -} - -void OSQPInterface::updateU(const std::vector & u_new) -{ - std::vector u_tmp(u_new.begin(), u_new.end()); - double * u_dyn = u_tmp.data(); - osqp_update_upper_bound(m_work.get(), u_dyn); -} - -void OSQPInterface::updateBounds( - const std::vector & l_new, const std::vector & u_new) -{ - std::vector l_tmp(l_new.begin(), l_new.end()); - std::vector u_tmp(u_new.begin(), u_new.end()); - double * l_dyn = l_tmp.data(); - double * u_dyn = u_tmp.data(); - osqp_update_bounds(m_work.get(), l_dyn, u_dyn); -} - -void OSQPInterface::updateEpsAbs(const double eps_abs) -{ - m_settings->eps_abs = eps_abs; // for default setting - if (m_work_initialized) { - osqp_update_eps_abs(m_work.get(), eps_abs); // for current work - } -} - -void OSQPInterface::updateEpsRel(const double eps_rel) -{ - m_settings->eps_rel = eps_rel; // for default setting - if (m_work_initialized) { - osqp_update_eps_rel(m_work.get(), eps_rel); // for current work - } -} - -void OSQPInterface::updateMaxIter(const int max_iter) -{ - m_settings->max_iter = max_iter; // for default setting - if (m_work_initialized) { - osqp_update_max_iter(m_work.get(), max_iter); // for current work - } -} - -void OSQPInterface::updateVerbose(const bool is_verbose) -{ - m_settings->verbose = is_verbose; // for default setting - if (m_work_initialized) { - osqp_update_verbose(m_work.get(), is_verbose); // for current work - } -} - -void OSQPInterface::updateRhoInterval(const int rho_interval) -{ - m_settings->adaptive_rho_interval = rho_interval; // for default setting -} - -void OSQPInterface::updateRho(const double rho) -{ - m_settings->rho = rho; - if (m_work_initialized) { - osqp_update_rho(m_work.get(), rho); - } -} - -void OSQPInterface::updateAlpha(const double alpha) -{ - m_settings->alpha = alpha; - if (m_work_initialized) { - osqp_update_alpha(m_work.get(), alpha); - } -} - -void OSQPInterface::updateScaling(const int scaling) -{ - m_settings->scaling = scaling; -} - -void OSQPInterface::updatePolish(const bool polish) -{ - m_settings->polish = polish; - if (m_work_initialized) { - osqp_update_polish(m_work.get(), polish); - } -} - -void OSQPInterface::updatePolishRefinementIteration(const int polish_refine_iter) -{ - if (polish_refine_iter < 0) { - std::cerr << "Polish refinement iterations must be positive" << std::endl; - return; - } - - m_settings->polish_refine_iter = polish_refine_iter; - if (m_work_initialized) { - osqp_update_polish_refine_iter(m_work.get(), polish_refine_iter); - } -} - -void OSQPInterface::updateCheckTermination(const int check_termination) -{ - if (check_termination < 0) { - std::cerr << "Check termination must be positive" << std::endl; - return; - } - - m_settings->check_termination = check_termination; - if (m_work_initialized) { - osqp_update_check_termination(m_work.get(), check_termination); - } -} - -bool OSQPInterface::setWarmStart( - const std::vector & primal_variables, const std::vector & dual_variables) -{ - return setPrimalVariables(primal_variables) && setDualVariables(dual_variables); -} - -bool OSQPInterface::setPrimalVariables(const std::vector & primal_variables) -{ - if (!m_work_initialized) { - return false; - } - - const auto result = osqp_warm_start_x(m_work.get(), primal_variables.data()); - if (result != 0) { - std::cerr << "Failed to set primal variables for warm start" << std::endl; - return false; - } - - return true; -} - -bool OSQPInterface::setDualVariables(const std::vector & dual_variables) -{ - if (!m_work_initialized) { - return false; - } - - const auto result = osqp_warm_start_y(m_work.get(), dual_variables.data()); - if (result != 0) { - std::cerr << "Failed to set dual variables for warm start" << std::endl; - return false; - } - - return true; -} - -int64_t OSQPInterface::initializeProblem( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) -{ - // check if arguments are valid - std::stringstream ss; - if (P.rows() != P.cols()) { - ss << "P.rows() and P.cols() are not the same. P.rows() = " << P.rows() - << ", P.cols() = " << P.cols(); - throw std::invalid_argument(ss.str()); - } - if (P.rows() != static_cast(q.size())) { - ss << "P.rows() and q.size() are not the same. P.rows() = " << P.rows() - << ", q.size() = " << q.size(); - throw std::invalid_argument(ss.str()); - } - if (P.rows() != A.cols()) { - ss << "P.rows() and A.cols() are not the same. P.rows() = " << P.rows() - << ", A.cols() = " << A.cols(); - throw std::invalid_argument(ss.str()); - } - if (A.rows() != static_cast(l.size())) { - ss << "A.rows() and l.size() are not the same. A.rows() = " << A.rows() - << ", l.size() = " << l.size(); - throw std::invalid_argument(ss.str()); - } - if (A.rows() != static_cast(u.size())) { - ss << "A.rows() and u.size() are not the same. A.rows() = " << A.rows() - << ", u.size() = " << u.size(); - throw std::invalid_argument(ss.str()); - } - - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - return initializeProblem(P_csc, A_csc, q, l, u); -} - -int64_t OSQPInterface::initializeProblem( - CSC_Matrix P_csc, CSC_Matrix A_csc, const std::vector & q, const std::vector & l, - const std::vector & u) -{ - // Dynamic float arrays - std::vector q_tmp(q.begin(), q.end()); - std::vector l_tmp(l.begin(), l.end()); - std::vector u_tmp(u.begin(), u.end()); - double * q_dyn = q_tmp.data(); - double * l_dyn = l_tmp.data(); - double * u_dyn = u_tmp.data(); - - /********************** - * OBJECTIVE FUNCTION - **********************/ - m_param_n = static_cast(q.size()); - m_data->m = static_cast(l.size()); - - /***************** - * POPULATE DATA - *****************/ - m_data->n = m_param_n; - if (m_data->P) free(m_data->P); - m_data->P = csc_matrix( - m_data->n, m_data->n, static_cast(P_csc.m_vals.size()), P_csc.m_vals.data(), - P_csc.m_row_idxs.data(), P_csc.m_col_idxs.data()); - m_data->q = q_dyn; - if (m_data->A) free(m_data->A); - m_data->A = csc_matrix( - m_data->m, m_data->n, static_cast(A_csc.m_vals.size()), A_csc.m_vals.data(), - A_csc.m_row_idxs.data(), A_csc.m_col_idxs.data()); - m_data->l = l_dyn; - m_data->u = u_dyn; - - // Setup workspace - OSQPWorkspace * workspace; - m_exitflag = osqp_setup(&workspace, m_data.get(), m_settings.get()); - m_work.reset(workspace); - m_work_initialized = true; - - return m_exitflag; -} - -std::tuple, std::vector, int64_t, int64_t, int64_t> -OSQPInterface::solve() -{ - // Solve Problem - osqp_solve(m_work.get()); - - /******************** - * EXTRACT SOLUTION - ********************/ - double * sol_x = m_work->solution->x; - double * sol_y = m_work->solution->y; - std::vector sol_primal(sol_x, sol_x + m_param_n); - std::vector sol_lagrange_multiplier(sol_y, sol_y + m_data->m); - - int64_t status_polish = m_work->info->status_polish; - int64_t status_solution = m_work->info->status_val; - int64_t status_iteration = m_work->info->iter; - - // Result tuple - std::tuple, std::vector, int64_t, int64_t, int64_t> result = - std::make_tuple( - sol_primal, sol_lagrange_multiplier, status_polish, status_solution, status_iteration); - - m_latest_work_info = *(m_work->info); - - return result; -} - -std::tuple, std::vector, int64_t, int64_t, int64_t> -OSQPInterface::optimize() -{ - // Run the solver on the stored problem representation. - std::tuple, std::vector, int64_t, int64_t, int64_t> result = solve(); - return result; -} - -std::tuple, std::vector, int64_t, int64_t, int64_t> -OSQPInterface::optimize( - const Eigen::MatrixXd & P, const Eigen::MatrixXd & A, const std::vector & q, - const std::vector & l, const std::vector & u) -{ - // Allocate memory for problem - initializeProblem(P, A, q, l, u); - - // Run the solver on the stored problem representation. - std::tuple, std::vector, int64_t, int64_t, int64_t> result = solve(); - - m_work.reset(); - m_work_initialized = false; - - return result; -} - -void OSQPInterface::logUnsolvedStatus(const std::string & prefix_message) const -{ - const int status = getStatus(); - if (status == 1) { - // No need to log since optimization was solved. - return; - } - - // create message - std::string output_message = ""; - if (prefix_message != "") { - output_message = prefix_message + " "; - } - - const auto status_message = getStatusMessage(); - output_message += "Optimization failed due to " + status_message; - - // log with warning - RCLCPP_WARN(rclcpp::get_logger("osqp_interface"), "%s", output_message.c_str()); -} -} // namespace autoware::osqp_interface diff --git a/common/autoware_osqp_interface/test/test_csc_matrix_conv.cpp b/common/autoware_osqp_interface/test/test_csc_matrix_conv.cpp deleted file mode 100644 index a63f979a966bf..0000000000000 --- a/common/autoware_osqp_interface/test/test_csc_matrix_conv.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2021 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/osqp_interface/csc_matrix_conv.hpp" -#include "gtest/gtest.h" - -#include - -#include -#include -#include - -TEST(TestCscMatrixConv, Nominal) -{ - using autoware::osqp_interface::calCSCMatrix; - using autoware::osqp_interface::CSC_Matrix; - - Eigen::MatrixXd rect1(1, 2); - rect1 << 0.0, 1.0; - - const CSC_Matrix rect_m1 = calCSCMatrix(rect1); - ASSERT_EQ(rect_m1.m_vals.size(), size_t(1)); - EXPECT_EQ(rect_m1.m_vals[0], 1.0); - ASSERT_EQ(rect_m1.m_row_idxs.size(), size_t(1)); - EXPECT_EQ(rect_m1.m_row_idxs[0], c_int(0)); - ASSERT_EQ(rect_m1.m_col_idxs.size(), size_t(3)); // nb of columns + 1 - EXPECT_EQ(rect_m1.m_col_idxs[0], c_int(0)); - EXPECT_EQ(rect_m1.m_col_idxs[1], c_int(0)); - EXPECT_EQ(rect_m1.m_col_idxs[2], c_int(1)); - - Eigen::MatrixXd rect2(2, 4); - rect2 << 1.0, 0.0, 3.0, 0.0, 0.0, 6.0, 7.0, 0.0; - - const CSC_Matrix rect_m2 = calCSCMatrix(rect2); - ASSERT_EQ(rect_m2.m_vals.size(), size_t(4)); - EXPECT_EQ(rect_m2.m_vals[0], 1.0); - EXPECT_EQ(rect_m2.m_vals[1], 6.0); - EXPECT_EQ(rect_m2.m_vals[2], 3.0); - EXPECT_EQ(rect_m2.m_vals[3], 7.0); - ASSERT_EQ(rect_m2.m_row_idxs.size(), size_t(4)); - EXPECT_EQ(rect_m2.m_row_idxs[0], c_int(0)); - EXPECT_EQ(rect_m2.m_row_idxs[1], c_int(1)); - EXPECT_EQ(rect_m2.m_row_idxs[2], c_int(0)); - EXPECT_EQ(rect_m2.m_row_idxs[3], c_int(1)); - ASSERT_EQ(rect_m2.m_col_idxs.size(), size_t(5)); // nb of columns + 1 - EXPECT_EQ(rect_m2.m_col_idxs[0], c_int(0)); - EXPECT_EQ(rect_m2.m_col_idxs[1], c_int(1)); - EXPECT_EQ(rect_m2.m_col_idxs[2], c_int(2)); - EXPECT_EQ(rect_m2.m_col_idxs[3], c_int(4)); - EXPECT_EQ(rect_m2.m_col_idxs[4], c_int(4)); - - // Example from http://netlib.org/linalg/html_templates/node92.html - Eigen::MatrixXd square2(6, 6); - square2 << 10.0, 0.0, 0.0, 0.0, -2.0, 0.0, 3.0, 9.0, 0.0, 0.0, 0.0, 3.0, 0.0, 7.0, 8.0, 7.0, 0.0, - 0.0, 3.0, 0.0, 8.0, 7.0, 5.0, 0.0, 0.0, 8.0, 0.0, 9.0, 9.0, 13.0, 0.0, 4.0, 0.0, 0.0, 2.0, -1.0; - - const CSC_Matrix square_m2 = calCSCMatrix(square2); - ASSERT_EQ(square_m2.m_vals.size(), size_t(19)); - EXPECT_EQ(square_m2.m_vals[0], 10.0); - EXPECT_EQ(square_m2.m_vals[1], 3.0); - EXPECT_EQ(square_m2.m_vals[2], 3.0); - EXPECT_EQ(square_m2.m_vals[3], 9.0); - EXPECT_EQ(square_m2.m_vals[4], 7.0); - EXPECT_EQ(square_m2.m_vals[5], 8.0); - EXPECT_EQ(square_m2.m_vals[6], 4.0); - EXPECT_EQ(square_m2.m_vals[7], 8.0); - EXPECT_EQ(square_m2.m_vals[8], 8.0); - EXPECT_EQ(square_m2.m_vals[9], 7.0); - EXPECT_EQ(square_m2.m_vals[10], 7.0); - EXPECT_EQ(square_m2.m_vals[11], 9.0); - EXPECT_EQ(square_m2.m_vals[12], -2.0); - EXPECT_EQ(square_m2.m_vals[13], 5.0); - EXPECT_EQ(square_m2.m_vals[14], 9.0); - EXPECT_EQ(square_m2.m_vals[15], 2.0); - EXPECT_EQ(square_m2.m_vals[16], 3.0); - EXPECT_EQ(square_m2.m_vals[17], 13.0); - EXPECT_EQ(square_m2.m_vals[18], -1.0); - ASSERT_EQ(square_m2.m_row_idxs.size(), size_t(19)); - EXPECT_EQ(square_m2.m_row_idxs[0], c_int(0)); - EXPECT_EQ(square_m2.m_row_idxs[1], c_int(1)); - EXPECT_EQ(square_m2.m_row_idxs[2], c_int(3)); - EXPECT_EQ(square_m2.m_row_idxs[3], c_int(1)); - EXPECT_EQ(square_m2.m_row_idxs[4], c_int(2)); - EXPECT_EQ(square_m2.m_row_idxs[5], c_int(4)); - EXPECT_EQ(square_m2.m_row_idxs[6], c_int(5)); - EXPECT_EQ(square_m2.m_row_idxs[7], c_int(2)); - EXPECT_EQ(square_m2.m_row_idxs[8], c_int(3)); - EXPECT_EQ(square_m2.m_row_idxs[9], c_int(2)); - EXPECT_EQ(square_m2.m_row_idxs[10], c_int(3)); - EXPECT_EQ(square_m2.m_row_idxs[11], c_int(4)); - EXPECT_EQ(square_m2.m_row_idxs[12], c_int(0)); - EXPECT_EQ(square_m2.m_row_idxs[13], c_int(3)); - EXPECT_EQ(square_m2.m_row_idxs[14], c_int(4)); - EXPECT_EQ(square_m2.m_row_idxs[15], c_int(5)); - EXPECT_EQ(square_m2.m_row_idxs[16], c_int(1)); - EXPECT_EQ(square_m2.m_row_idxs[17], c_int(4)); - EXPECT_EQ(square_m2.m_row_idxs[18], c_int(5)); - ASSERT_EQ(square_m2.m_col_idxs.size(), size_t(7)); // nb of columns + 1 - EXPECT_EQ(square_m2.m_col_idxs[0], c_int(0)); - EXPECT_EQ(square_m2.m_col_idxs[1], c_int(3)); - EXPECT_EQ(square_m2.m_col_idxs[2], c_int(7)); - EXPECT_EQ(square_m2.m_col_idxs[3], c_int(9)); - EXPECT_EQ(square_m2.m_col_idxs[4], c_int(12)); - EXPECT_EQ(square_m2.m_col_idxs[5], c_int(16)); - EXPECT_EQ(square_m2.m_col_idxs[6], c_int(19)); -} -TEST(TestCscMatrixConv, Trapezoidal) -{ - using autoware::osqp_interface::calCSCMatrixTrapezoidal; - using autoware::osqp_interface::CSC_Matrix; - - Eigen::MatrixXd square1(2, 2); - Eigen::MatrixXd square2(3, 3); - Eigen::MatrixXd rect1(1, 2); - square1 << 1.0, 2.0, 2.0, 4.0; - square2 << 0.0, 2.0, 0.0, 4.0, 5.0, 6.0, 0.0, 0.0, 0.0; - rect1 << 0.0, 1.0; - - const CSC_Matrix square_m1 = calCSCMatrixTrapezoidal(square1); - // Trapezoidal: skip the lower left triangle (2.0 in this example) - ASSERT_EQ(square_m1.m_vals.size(), size_t(3)); - EXPECT_EQ(square_m1.m_vals[0], 1.0); - EXPECT_EQ(square_m1.m_vals[1], 2.0); - EXPECT_EQ(square_m1.m_vals[2], 4.0); - ASSERT_EQ(square_m1.m_row_idxs.size(), size_t(3)); - EXPECT_EQ(square_m1.m_row_idxs[0], c_int(0)); - EXPECT_EQ(square_m1.m_row_idxs[1], c_int(0)); - EXPECT_EQ(square_m1.m_row_idxs[2], c_int(1)); - ASSERT_EQ(square_m1.m_col_idxs.size(), size_t(3)); - EXPECT_EQ(square_m1.m_col_idxs[0], c_int(0)); - EXPECT_EQ(square_m1.m_col_idxs[1], c_int(1)); - EXPECT_EQ(square_m1.m_col_idxs[2], c_int(3)); - - const CSC_Matrix square_m2 = calCSCMatrixTrapezoidal(square2); - ASSERT_EQ(square_m2.m_vals.size(), size_t(3)); - EXPECT_EQ(square_m2.m_vals[0], 2.0); - EXPECT_EQ(square_m2.m_vals[1], 5.0); - EXPECT_EQ(square_m2.m_vals[2], 6.0); - ASSERT_EQ(square_m2.m_row_idxs.size(), size_t(3)); - EXPECT_EQ(square_m2.m_row_idxs[0], c_int(0)); - EXPECT_EQ(square_m2.m_row_idxs[1], c_int(1)); - EXPECT_EQ(square_m2.m_row_idxs[2], c_int(1)); - ASSERT_EQ(square_m2.m_col_idxs.size(), size_t(4)); - EXPECT_EQ(square_m2.m_col_idxs[0], c_int(0)); - EXPECT_EQ(square_m2.m_col_idxs[1], c_int(0)); - EXPECT_EQ(square_m2.m_col_idxs[2], c_int(2)); - EXPECT_EQ(square_m2.m_col_idxs[3], c_int(3)); - - try { - const CSC_Matrix rect_m1 = calCSCMatrixTrapezoidal(rect1); - FAIL() << "calCSCMatrixTrapezoidal should fail with non-square inputs"; - } catch (const std::invalid_argument & e) { - EXPECT_EQ(e.what(), std::string("Matrix must be square (n, n)")); - } -} -TEST(TestCscMatrixConv, Print) -{ - using autoware::osqp_interface::calCSCMatrix; - using autoware::osqp_interface::calCSCMatrixTrapezoidal; - using autoware::osqp_interface::CSC_Matrix; - using autoware::osqp_interface::printCSCMatrix; - Eigen::MatrixXd square1(2, 2); - Eigen::MatrixXd rect1(1, 2); - square1 << 1.0, 2.0, 2.0, 4.0; - rect1 << 0.0, 1.0; - const CSC_Matrix square_m1 = calCSCMatrixTrapezoidal(square1); - const CSC_Matrix rect_m1 = calCSCMatrix(rect1); - printCSCMatrix(square_m1); - printCSCMatrix(rect_m1); -} diff --git a/common/autoware_osqp_interface/test/test_osqp_interface.cpp b/common/autoware_osqp_interface/test/test_osqp_interface.cpp deleted file mode 100644 index f65b07e6d792d..0000000000000 --- a/common/autoware_osqp_interface/test/test_osqp_interface.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2021 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/osqp_interface/osqp_interface.hpp" -#include "gtest/gtest.h" - -#include - -#include -#include -#include - -namespace -{ -// Problem taken from https://github.com/osqp/osqp/blob/master/tests/basic_qp/generate_problem.py -// -// min 1/2 * x' * P * x + q' * x -// s.t. lb <= A * x <= ub -// -// P = [4, 1], q = [1], A = [1, 1], lb = [ 1], ub = [1.0] -// [1, 2] [1] [1, 0] [ 0] [0.7] -// [0, 1] [ 0] [0.7] -// [0, 1] [-inf] [inf] -// -// The optimal solution is -// x = [0.3, 0.7]' -// y = [-2.9, 0.0, 0.2, 0.0]` -// obj = 1.88 - -TEST(TestOsqpInterface, BasicQp) -{ - using autoware::osqp_interface::calCSCMatrix; - using autoware::osqp_interface::calCSCMatrixTrapezoidal; - using autoware::osqp_interface::CSC_Matrix; - - auto check_result = - [](const std::tuple, std::vector, int, int, int> & result) { - EXPECT_EQ(std::get<2>(result), 1); // polish succeeded - EXPECT_EQ(std::get<3>(result), 1); // solution succeeded - - static const auto ep = 1.0e-8; - - const auto prime_val = std::get<0>(result); - ASSERT_EQ(prime_val.size(), size_t(2)); - EXPECT_NEAR(prime_val[0], 0.3, ep); - EXPECT_NEAR(prime_val[1], 0.7, ep); - - const auto dual_val = std::get<1>(result); - ASSERT_EQ(dual_val.size(), size_t(4)); - EXPECT_NEAR(dual_val[0], -2.9, ep); - EXPECT_NEAR(dual_val[1], 0.0, ep); - EXPECT_NEAR(dual_val[2], 0.2, ep); - EXPECT_NEAR(dual_val[3], 0.0, ep); - }; - - const Eigen::MatrixXd P = (Eigen::MatrixXd(2, 2) << 4, 1, 1, 2).finished(); - const Eigen::MatrixXd A = (Eigen::MatrixXd(4, 2) << 1, 1, 1, 0, 0, 1, 0, 1).finished(); - const std::vector q = {1.0, 1.0}; - const std::vector l = {1.0, 0.0, 0.0, -autoware::osqp_interface::INF}; - const std::vector u = {1.0, 0.7, 0.7, autoware::osqp_interface::INF}; - - { - // Define problem during optimization - autoware::osqp_interface::OSQPInterface osqp; - std::tuple, std::vector, int, int, int> result = - osqp.optimize(P, A, q, l, u); - check_result(result); - } - - { - // Define problem during initialization - autoware::osqp_interface::OSQPInterface osqp(P, A, q, l, u, 1e-6); - std::tuple, std::vector, int, int, int> result = osqp.optimize(); - check_result(result); - } - - { - std::tuple, std::vector, int, int, int> result; - // Dummy initial problem - Eigen::MatrixXd P_ini = Eigen::MatrixXd::Zero(2, 2); - Eigen::MatrixXd A_ini = Eigen::MatrixXd::Zero(4, 2); - std::vector q_ini(2, 0.0); - std::vector l_ini(4, 0.0); - std::vector u_ini(4, 0.0); - autoware::osqp_interface::OSQPInterface osqp(P_ini, A_ini, q_ini, l_ini, u_ini, 1e-6); - osqp.optimize(); - - // Redefine problem before optimization - osqp.initializeProblem(P, A, q, l, u); - result = osqp.optimize(); - check_result(result); - } - - { - // Define problem during initialization with csc matrix - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - autoware::osqp_interface::OSQPInterface osqp(P_csc, A_csc, q, l, u, 1e-6); - std::tuple, std::vector, int, int, int> result = osqp.optimize(); - check_result(result); - } - - { - std::tuple, std::vector, int, int, int> result; - // Dummy initial problem with csc matrix - CSC_Matrix P_ini_csc = calCSCMatrixTrapezoidal(Eigen::MatrixXd::Zero(2, 2)); - CSC_Matrix A_ini_csc = calCSCMatrix(Eigen::MatrixXd::Zero(4, 2)); - std::vector q_ini(2, 0.0); - std::vector l_ini(4, 0.0); - std::vector u_ini(4, 0.0); - autoware::osqp_interface::OSQPInterface osqp(P_ini_csc, A_ini_csc, q_ini, l_ini, u_ini, 1e-6); - osqp.optimize(); - - // Redefine problem before optimization - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - osqp.initializeProblem(P_csc, A_csc, q, l, u); - result = osqp.optimize(); - check_result(result); - } - - // add warm startup - { - std::tuple, std::vector, int, int, int> result; - // Dummy initial problem with csc matrix - CSC_Matrix P_ini_csc = calCSCMatrixTrapezoidal(Eigen::MatrixXd::Zero(2, 2)); - CSC_Matrix A_ini_csc = calCSCMatrix(Eigen::MatrixXd::Zero(4, 2)); - std::vector q_ini(2, 0.0); - std::vector l_ini(4, 0.0); - std::vector u_ini(4, 0.0); - autoware::osqp_interface::OSQPInterface osqp(P_ini_csc, A_ini_csc, q_ini, l_ini, u_ini, 1e-6); - osqp.optimize(); - - // Redefine problem before optimization - CSC_Matrix P_csc = calCSCMatrixTrapezoidal(P); - CSC_Matrix A_csc = calCSCMatrix(A); - osqp.initializeProblem(P_csc, A_csc, q, l, u); - result = osqp.optimize(); - check_result(result); - - osqp.updateCheckTermination(1); - const auto primal_val = std::get<0>(result); - const auto dual_val = std::get<1>(result); - for (size_t i = 0; i < primal_val.size(); ++i) { - std::cerr << primal_val.at(i) << std::endl; - } - osqp.setWarmStart(primal_val, dual_val); - result = osqp.optimize(); - check_result(result); - EXPECT_EQ(osqp.getTakenIter(), 1); - } -} -} // namespace From a6b5f3c6992e6978eec4c110d1956df99c0219ca Mon Sep 17 00:00:00 2001 From: cyn-liu <104069308+cyn-liu@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:17:04 +0800 Subject: [PATCH 21/61] feat(autoware_kalman_filter): move autoware_kalman_filter to autowar.core (#9872) feat(autoware_kalman_filter): move autoware_kalman_filter to autoware.core Signed-off-by: liu cui --- common/autoware_kalman_filter/CHANGELOG.rst | 55 ----- common/autoware_kalman_filter/CMakeLists.txt | 29 --- common/autoware_kalman_filter/README.md | 9 - .../autoware/kalman_filter/kalman_filter.hpp | 214 ------------------ .../time_delay_kalman_filter.hpp | 89 -------- common/autoware_kalman_filter/package.xml | 28 --- .../src/kalman_filter.cpp | 161 ------------- .../src/time_delay_kalman_filter.cpp | 109 --------- .../test/test_kalman_filter.cpp | 96 -------- .../test/test_time_delay_kalman_filter.cpp | 123 ---------- 10 files changed, 913 deletions(-) delete mode 100644 common/autoware_kalman_filter/CHANGELOG.rst delete mode 100644 common/autoware_kalman_filter/CMakeLists.txt delete mode 100644 common/autoware_kalman_filter/README.md delete mode 100644 common/autoware_kalman_filter/include/autoware/kalman_filter/kalman_filter.hpp delete mode 100644 common/autoware_kalman_filter/include/autoware/kalman_filter/time_delay_kalman_filter.hpp delete mode 100644 common/autoware_kalman_filter/package.xml delete mode 100644 common/autoware_kalman_filter/src/kalman_filter.cpp delete mode 100644 common/autoware_kalman_filter/src/time_delay_kalman_filter.cpp delete mode 100644 common/autoware_kalman_filter/test/test_kalman_filter.cpp delete mode 100644 common/autoware_kalman_filter/test/test_time_delay_kalman_filter.cpp diff --git a/common/autoware_kalman_filter/CHANGELOG.rst b/common/autoware_kalman_filter/CHANGELOG.rst deleted file mode 100644 index a7e68f8843e74..0000000000000 --- a/common/autoware_kalman_filter/CHANGELOG.rst +++ /dev/null @@ -1,55 +0,0 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Changelog for package autoware_kalman_filter -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -0.40.0 (2024-12-12) -------------------- -* Merge branch 'main' into release-0.40.0 -* Revert "chore(package.xml): bump version to 0.39.0 (`#9587 `_)" - This reverts commit c9f0f2688c57b0f657f5c1f28f036a970682e7f5. -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* chore(package.xml): bump version to 0.39.0 (`#9587 `_) - * chore(package.xml): bump version to 0.39.0 - * fix: fix ticket links in CHANGELOG.rst - * fix: remove unnecessary diff - --------- - Co-authored-by: Yutaka Kondo -* fix: fix ticket links in CHANGELOG.rst (`#9588 `_) -* fix(cpplint): include what you use - common (`#9564 `_) -* 0.39.0 -* update changelog -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* Contributors: Esteve Fernandez, Fumiya Watanabe, M. Fatih Cırıt, Ryohsuke Mitsudome, Yutaka Kondo - -0.39.0 (2024-11-25) -------------------- -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* fix: fix ticket links to point to https://github.com/autowarefoundation/autoware.universe (`#9304 `_) -* chore(package.xml): bump version to 0.38.0 (`#9266 `_) (`#9284 `_) - * unify package.xml version to 0.37.0 - * remove system_monitor/CHANGELOG.rst - * add changelog - * 0.38.0 - --------- -* Contributors: Esteve Fernandez, Yutaka Kondo - -0.38.0 (2024-11-08) -------------------- -* unify package.xml version to 0.37.0 -* refactor(kalman_filter): prefix package and namespace with autoware (`#7787 `_) - * refactor(kalman_filter): prefix package and namespace with autoware - * move headers to include/autoware/ - * style(pre-commit): autofix - --------- - Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> -* Contributors: Esteve Fernandez, Yutaka Kondo - -0.26.0 (2024-04-03) -------------------- diff --git a/common/autoware_kalman_filter/CMakeLists.txt b/common/autoware_kalman_filter/CMakeLists.txt deleted file mode 100644 index 076d2d3cad4e8..0000000000000 --- a/common/autoware_kalman_filter/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(autoware_kalman_filter) - -find_package(autoware_cmake REQUIRED) -autoware_package() - -find_package(eigen3_cmake_module REQUIRED) -find_package(Eigen3 REQUIRED) - -include_directories( - SYSTEM - ${EIGEN3_INCLUDE_DIR} -) - -ament_auto_add_library(${PROJECT_NAME} SHARED - src/kalman_filter.cpp - src/time_delay_kalman_filter.cpp - include/autoware/kalman_filter/kalman_filter.hpp - include/autoware/kalman_filter/time_delay_kalman_filter.hpp -) - -if(BUILD_TESTING) - file(GLOB_RECURSE test_files test/*.cpp) - ament_add_ros_isolated_gtest(test_${PROJECT_NAME} ${test_files}) - - target_link_libraries(test_${PROJECT_NAME} ${PROJECT_NAME}) -endif() - -ament_auto_package() diff --git a/common/autoware_kalman_filter/README.md b/common/autoware_kalman_filter/README.md deleted file mode 100644 index 7c0feb9c2a61a..0000000000000 --- a/common/autoware_kalman_filter/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# kalman_filter - -## Purpose - -This common package contains the kalman filter with time delay and the calculation of the kalman filter. - -## Assumptions / Known limits - -TBD. diff --git a/common/autoware_kalman_filter/include/autoware/kalman_filter/kalman_filter.hpp b/common/autoware_kalman_filter/include/autoware/kalman_filter/kalman_filter.hpp deleted file mode 100644 index 74db04f6e838b..0000000000000 --- a/common/autoware_kalman_filter/include/autoware/kalman_filter/kalman_filter.hpp +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2018-2019 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__KALMAN_FILTER__KALMAN_FILTER_HPP_ -#define AUTOWARE__KALMAN_FILTER__KALMAN_FILTER_HPP_ - -#include -#include - -namespace autoware::kalman_filter -{ - -/** - * @file kalman_filter.h - * @brief kalman filter class - * @author Takamasa Horibe - * @date 2019.05.01 - */ - -class KalmanFilter -{ -public: - /** - * @brief No initialization constructor. - */ - KalmanFilter(); - - /** - * @brief constructor with initialization - * @param x initial state - * @param A coefficient matrix of x for process model - * @param B coefficient matrix of u for process model - * @param C coefficient matrix of x for measurement model - * @param Q covariance matrix for process model - * @param R covariance matrix for measurement model - * @param P initial covariance of estimated state - */ - KalmanFilter( - const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B, - const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R, - const Eigen::MatrixXd & P); - - /** - * @brief destructor - */ - ~KalmanFilter(); - - /** - * @brief initialization of kalman filter - * @param x initial state - * @param A coefficient matrix of x for process model - * @param B coefficient matrix of u for process model - * @param C coefficient matrix of x for measurement model - * @param Q covariance matrix for process model - * @param R covariance matrix for measurement model - * @param P initial covariance of estimated state - */ - bool init( - const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B, - const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R, - const Eigen::MatrixXd & P); - - /** - * @brief initialization of kalman filter - * @param x initial state - * @param P initial covariance of estimated state - */ - bool init(const Eigen::MatrixXd & x, const Eigen::MatrixXd & P0); - - /** - * @brief set A of process model - * @param A coefficient matrix of x for process model - */ - void setA(const Eigen::MatrixXd & A); - - /** - * @brief set B of process model - * @param B coefficient matrix of u for process model - */ - void setB(const Eigen::MatrixXd & B); - - /** - * @brief set C of measurement model - * @param C coefficient matrix of x for measurement model - */ - void setC(const Eigen::MatrixXd & C); - - /** - * @brief set covariance matrix Q for process model - * @param Q covariance matrix for process model - */ - void setQ(const Eigen::MatrixXd & Q); - - /** - * @brief set covariance matrix R for measurement model - * @param R covariance matrix for measurement model - */ - void setR(const Eigen::MatrixXd & R); - - /** - * @brief get current kalman filter state - * @param x kalman filter state - */ - void getX(Eigen::MatrixXd & x) const; - - /** - * @brief get current kalman filter covariance - * @param P kalman filter covariance - */ - void getP(Eigen::MatrixXd & P) const; - - /** - * @brief get component of current kalman filter state - * @param i index of kalman filter state - * @return value of i's component of the kalman filter state x[i] - */ - double getXelement(unsigned int i) const; - - /** - * @brief calculate kalman filter state and covariance by prediction model with A, B, Q matrix. - * This is mainly for EKF with variable matrix. - * @param u input for model - * @param A coefficient matrix of x for process model - * @param B coefficient matrix of u for process model - * @param Q covariance matrix for process model - * @return bool to check matrix operations are being performed properly - */ - bool predict( - const Eigen::MatrixXd & u, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B, - const Eigen::MatrixXd & Q); - - /** - * @brief calculate kalman filter covariance with prediction model with x, A, Q matrix. This is - * mainly for EKF with variable matrix. - * @param x_next predicted state - * @param A coefficient matrix of x for process model - * @param Q covariance matrix for process model - * @return bool to check matrix operations are being performed properly - */ - bool predict( - const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q); - - /** - * @brief calculate kalman filter covariance with prediction model with x, A, Q matrix. This is - * mainly for EKF with variable matrix. - * @param x_next predicted state - * @param A coefficient matrix of x for process model - * @return bool to check matrix operations are being performed properly - */ - bool predict(const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A); - - /** - * @brief calculate kalman filter state by prediction model with A, B and Q being class member - * variables. - * @param u input for the model - * @return bool to check matrix operations are being performed properly - */ - bool predict(const Eigen::MatrixXd & u); - - /** - * @brief calculate kalman filter state by measurement model with y_pred, C and R matrix. This is - * mainly for EKF with variable matrix. - * @param y measured values - * @param y output values expected from measurement model - * @param C coefficient matrix of x for measurement model - * @param R covariance matrix for measurement model - * @return bool to check matrix operations are being performed properly - */ - bool update( - const Eigen::MatrixXd & y, const Eigen::MatrixXd & y_pred, const Eigen::MatrixXd & C, - const Eigen::MatrixXd & R); - - /** - * @brief calculate kalman filter state by measurement model with C and R matrix. This is mainly - * for EKF with variable matrix. - * @param y measured values - * @param C coefficient matrix of x for measurement model - * @param R covariance matrix for measurement model - * @return bool to check matrix operations are being performed properly - */ - bool update(const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R); - - /** - * @brief calculate kalman filter state by measurement model with C and R being class member - * variables. - * @param y measured values - * @return bool to check matrix operations are being performed properly - */ - bool update(const Eigen::MatrixXd & y); - -protected: - Eigen::MatrixXd x_; //!< @brief current estimated state - Eigen::MatrixXd - A_; //!< @brief coefficient matrix of x for process model x[k+1] = A*x[k] + B*u[k] - Eigen::MatrixXd - B_; //!< @brief coefficient matrix of u for process model x[k+1] = A*x[k] + B*u[k] - Eigen::MatrixXd C_; //!< @brief coefficient matrix of x for measurement model y[k] = C * x[k] - Eigen::MatrixXd Q_; //!< @brief covariance matrix for process model x[k+1] = A*x[k] + B*u[k] - Eigen::MatrixXd R_; //!< @brief covariance matrix for measurement model y[k] = C * x[k] - Eigen::MatrixXd P_; //!< @brief covariance of estimated state -}; -} // namespace autoware::kalman_filter -#endif // AUTOWARE__KALMAN_FILTER__KALMAN_FILTER_HPP_ diff --git a/common/autoware_kalman_filter/include/autoware/kalman_filter/time_delay_kalman_filter.hpp b/common/autoware_kalman_filter/include/autoware/kalman_filter/time_delay_kalman_filter.hpp deleted file mode 100644 index 80375b7579e62..0000000000000 --- a/common/autoware_kalman_filter/include/autoware/kalman_filter/time_delay_kalman_filter.hpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2018-2019 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__KALMAN_FILTER__TIME_DELAY_KALMAN_FILTER_HPP_ -#define AUTOWARE__KALMAN_FILTER__TIME_DELAY_KALMAN_FILTER_HPP_ - -#include "autoware/kalman_filter/kalman_filter.hpp" - -#include -#include - -#include - -namespace autoware::kalman_filter -{ -/** - * @file time_delay_kalman_filter.h - * @brief kalman filter with delayed measurement class - * @author Takamasa Horibe - * @date 2019.05.01 - */ - -class TimeDelayKalmanFilter : public KalmanFilter -{ -public: - /** - * @brief No initialization constructor. - */ - TimeDelayKalmanFilter(); - - /** - * @brief initialization of kalman filter - * @param x initial state - * @param P0 initial covariance of estimated state - * @param max_delay_step Maximum number of delay steps, which determines the dimension of the - * extended kalman filter - */ - void init(const Eigen::MatrixXd & x, const Eigen::MatrixXd & P, const int max_delay_step); - - /** - * @brief get latest time estimated state - */ - Eigen::MatrixXd getLatestX() const; - - /** - * @brief get latest time estimation covariance - */ - Eigen::MatrixXd getLatestP() const; - - /** - * @brief calculate kalman filter covariance by precision model with time delay. This is mainly - * for EKF of nonlinear process model. - * @param x_next predicted state by prediction model - * @param A coefficient matrix of x for process model - * @param Q covariance matrix for process model - */ - bool predictWithDelay( - const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q); - - /** - * @brief calculate kalman filter covariance by measurement model with time delay. This is mainly - * for EKF of nonlinear process model. - * @param y measured values - * @param C coefficient matrix of x for measurement model - * @param R covariance matrix for measurement model - * @param delay_step measurement delay - */ - bool updateWithDelay( - const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R, - const int delay_step); - -private: - int max_delay_step_; //!< @brief maximum number of delay steps - int dim_x_; //!< @brief dimension of latest state - int dim_x_ex_; //!< @brief dimension of extended state with dime delay -}; -} // namespace autoware::kalman_filter -#endif // AUTOWARE__KALMAN_FILTER__TIME_DELAY_KALMAN_FILTER_HPP_ diff --git a/common/autoware_kalman_filter/package.xml b/common/autoware_kalman_filter/package.xml deleted file mode 100644 index e51bb06e9de43..0000000000000 --- a/common/autoware_kalman_filter/package.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - autoware_kalman_filter - 0.40.0 - The kalman filter package - Yukihiro Saito - Takeshi Ishita - Koji Minoda - Apache License 2.0 - - Takamasa Horibe - - ament_cmake_auto - autoware_cmake - - eigen - eigen3_cmake_module - - ament_cmake_cppcheck - ament_cmake_ros - ament_lint_auto - autoware_lint_common - - - ament_cmake - - diff --git a/common/autoware_kalman_filter/src/kalman_filter.cpp b/common/autoware_kalman_filter/src/kalman_filter.cpp deleted file mode 100644 index bbd963675f9e2..0000000000000 --- a/common/autoware_kalman_filter/src/kalman_filter.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2018-2019 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/kalman_filter/kalman_filter.hpp" - -namespace autoware::kalman_filter -{ -KalmanFilter::KalmanFilter() -{ -} -KalmanFilter::KalmanFilter( - const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B, - const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R, - const Eigen::MatrixXd & P) -{ - init(x, A, B, C, Q, R, P); -} -KalmanFilter::~KalmanFilter() -{ -} -bool KalmanFilter::init( - const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B, - const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R, - const Eigen::MatrixXd & P) -{ - if ( - x.cols() == 0 || x.rows() == 0 || A.cols() == 0 || A.rows() == 0 || B.cols() == 0 || - B.rows() == 0 || C.cols() == 0 || C.rows() == 0 || Q.cols() == 0 || Q.rows() == 0 || - R.cols() == 0 || R.rows() == 0 || P.cols() == 0 || P.rows() == 0) { - return false; - } - x_ = x; - A_ = A; - B_ = B; - C_ = C; - Q_ = Q; - R_ = R; - P_ = P; - return true; -} -bool KalmanFilter::init(const Eigen::MatrixXd & x, const Eigen::MatrixXd & P0) -{ - if (x.cols() == 0 || x.rows() == 0 || P0.cols() == 0 || P0.rows() == 0) { - return false; - } - x_ = x; - P_ = P0; - return true; -} - -void KalmanFilter::setA(const Eigen::MatrixXd & A) -{ - A_ = A; -} -void KalmanFilter::setB(const Eigen::MatrixXd & B) -{ - B_ = B; -} -void KalmanFilter::setC(const Eigen::MatrixXd & C) -{ - C_ = C; -} -void KalmanFilter::setQ(const Eigen::MatrixXd & Q) -{ - Q_ = Q; -} -void KalmanFilter::setR(const Eigen::MatrixXd & R) -{ - R_ = R; -} -void KalmanFilter::getX(Eigen::MatrixXd & x) const -{ - x = x_; -} -void KalmanFilter::getP(Eigen::MatrixXd & P) const -{ - P = P_; -} -double KalmanFilter::getXelement(unsigned int i) const -{ - return x_(i); -} - -bool KalmanFilter::predict( - const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q) -{ - if ( - x_.rows() != x_next.rows() || A.cols() != P_.rows() || Q.cols() != Q.rows() || - A.rows() != Q.cols()) { - return false; - } - x_ = x_next; - P_ = A * P_ * A.transpose() + Q; - return true; -} -bool KalmanFilter::predict(const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A) -{ - return predict(x_next, A, Q_); -} - -bool KalmanFilter::predict( - const Eigen::MatrixXd & u, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B, - const Eigen::MatrixXd & Q) -{ - if (A.cols() != x_.rows() || B.cols() != u.rows()) { - return false; - } - const Eigen::MatrixXd x_next = A * x_ + B * u; - return predict(x_next, A, Q); -} -bool KalmanFilter::predict(const Eigen::MatrixXd & u) -{ - return predict(u, A_, B_, Q_); -} - -bool KalmanFilter::update( - const Eigen::MatrixXd & y, const Eigen::MatrixXd & y_pred, const Eigen::MatrixXd & C, - const Eigen::MatrixXd & R) -{ - if ( - P_.cols() != C.cols() || R.rows() != R.cols() || R.rows() != C.rows() || - y.rows() != y_pred.rows() || y.rows() != C.rows()) { - return false; - } - const Eigen::MatrixXd PCT = P_ * C.transpose(); - const Eigen::MatrixXd K = PCT * ((R + C * PCT).inverse()); - - if (isnan(K.array()).any() || isinf(K.array()).any()) { - return false; - } - - x_ = x_ + K * (y - y_pred); - P_ = P_ - K * (C * P_); - return true; -} - -bool KalmanFilter::update( - const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R) -{ - if (C.cols() != x_.rows()) { - return false; - } - const Eigen::MatrixXd y_pred = C * x_; - return update(y, y_pred, C, R); -} -bool KalmanFilter::update(const Eigen::MatrixXd & y) -{ - return update(y, C_, R_); -} -} // namespace autoware::kalman_filter diff --git a/common/autoware_kalman_filter/src/time_delay_kalman_filter.cpp b/common/autoware_kalman_filter/src/time_delay_kalman_filter.cpp deleted file mode 100644 index 4d1dd8f33b7a6..0000000000000 --- a/common/autoware_kalman_filter/src/time_delay_kalman_filter.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2018-2019 Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/kalman_filter/time_delay_kalman_filter.hpp" - -#include - -namespace autoware::kalman_filter -{ -TimeDelayKalmanFilter::TimeDelayKalmanFilter() -{ -} - -void TimeDelayKalmanFilter::init( - const Eigen::MatrixXd & x, const Eigen::MatrixXd & P0, const int max_delay_step) -{ - max_delay_step_ = max_delay_step; - dim_x_ = x.rows(); - dim_x_ex_ = dim_x_ * max_delay_step; - - x_ = Eigen::MatrixXd::Zero(dim_x_ex_, 1); - P_ = Eigen::MatrixXd::Zero(dim_x_ex_, dim_x_ex_); - - for (int i = 0; i < max_delay_step_; ++i) { - x_.block(i * dim_x_, 0, dim_x_, 1) = x; - P_.block(i * dim_x_, i * dim_x_, dim_x_, dim_x_) = P0; - } -} - -Eigen::MatrixXd TimeDelayKalmanFilter::getLatestX() const -{ - return x_.block(0, 0, dim_x_, 1); -} - -Eigen::MatrixXd TimeDelayKalmanFilter::getLatestP() const -{ - return P_.block(0, 0, dim_x_, dim_x_); -} - -bool TimeDelayKalmanFilter::predictWithDelay( - const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q) -{ - /* - * time delay model: - * - * [A 0 0] [P11 P12 P13] [Q 0 0] - * A = [I 0 0], P = [P21 P22 P23], Q = [0 0 0] - * [0 I 0] [P31 P32 P33] [0 0 0] - * - * covariance calculation in prediction : P = A * P * A' + Q - * - * [A*P11*A'*+Q A*P11 A*P12] - * P = [ P11*A' P11 P12] - * [ P21*A' P21 P22] - */ - - const int d_dim_x = dim_x_ex_ - dim_x_; - - /* slide states in the time direction */ - Eigen::MatrixXd x_tmp = Eigen::MatrixXd::Zero(dim_x_ex_, 1); - x_tmp.block(0, 0, dim_x_, 1) = x_next; - x_tmp.block(dim_x_, 0, d_dim_x, 1) = x_.block(0, 0, d_dim_x, 1); - x_ = x_tmp; - - /* update P with delayed measurement A matrix structure */ - Eigen::MatrixXd P_tmp = Eigen::MatrixXd::Zero(dim_x_ex_, dim_x_ex_); - P_tmp.block(0, 0, dim_x_, dim_x_) = A * P_.block(0, 0, dim_x_, dim_x_) * A.transpose() + Q; - P_tmp.block(0, dim_x_, dim_x_, d_dim_x) = A * P_.block(0, 0, dim_x_, d_dim_x); - P_tmp.block(dim_x_, 0, d_dim_x, dim_x_) = P_.block(0, 0, d_dim_x, dim_x_) * A.transpose(); - P_tmp.block(dim_x_, dim_x_, d_dim_x, d_dim_x) = P_.block(0, 0, d_dim_x, d_dim_x); - P_ = P_tmp; - - return true; -} - -bool TimeDelayKalmanFilter::updateWithDelay( - const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R, - const int delay_step) -{ - if (delay_step >= max_delay_step_) { - std::cerr << "delay step is larger than max_delay_step. ignore update." << std::endl; - return false; - } - - const int dim_y = y.rows(); - - /* set measurement matrix */ - Eigen::MatrixXd C_ex = Eigen::MatrixXd::Zero(dim_y, dim_x_ex_); - C_ex.block(0, dim_x_ * delay_step, dim_y, dim_x_) = C; - - /* update */ - if (!update(y, C_ex, R)) { - return false; - } - - return true; -} -} // namespace autoware::kalman_filter diff --git a/common/autoware_kalman_filter/test/test_kalman_filter.cpp b/common/autoware_kalman_filter/test/test_kalman_filter.cpp deleted file mode 100644 index 34e23ef9d06e2..0000000000000 --- a/common/autoware_kalman_filter/test/test_kalman_filter.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2023 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/kalman_filter/kalman_filter.hpp" - -#include - -using autoware::kalman_filter::KalmanFilter; - -TEST(kalman_filter, kf) -{ - KalmanFilter kf_; - - Eigen::MatrixXd x_t(2, 1); - x_t << 1, 2; - - Eigen::MatrixXd P_t(2, 2); - P_t << 1, 0, 0, 1; - - Eigen::MatrixXd Q_t(2, 2); - Q_t << 0.01, 0, 0, 0.01; - - Eigen::MatrixXd R_t(2, 2); - R_t << 0.09, 0, 0, 0.09; - - Eigen::MatrixXd C_t(2, 2); - C_t << 1, 0, 0, 1; - - Eigen::MatrixXd A_t(2, 2); - A_t << 1, 0, 0, 1; - - Eigen::MatrixXd B_t(2, 2); - B_t << 1, 0, 0, 1; - - // Initialize the filter and check if initialization was successful - EXPECT_TRUE(kf_.init(x_t, A_t, B_t, C_t, Q_t, R_t, P_t)); - - // Perform prediction - Eigen::MatrixXd u_t(2, 1); - u_t << 0.1, 0.1; - EXPECT_TRUE(kf_.predict(u_t)); - - // Check the updated state and covariance matrix - Eigen::MatrixXd x_predict_expected = A_t * x_t + B_t * u_t; - Eigen::MatrixXd P_predict_expected = A_t * P_t * A_t.transpose() + Q_t; - - Eigen::MatrixXd x_predict; - kf_.getX(x_predict); - Eigen::MatrixXd P_predict; - kf_.getP(P_predict); - - EXPECT_NEAR(x_predict(0, 0), x_predict_expected(0, 0), 1e-5); - EXPECT_NEAR(x_predict(1, 0), x_predict_expected(1, 0), 1e-5); - EXPECT_NEAR(P_predict(0, 0), P_predict_expected(0, 0), 1e-5); - EXPECT_NEAR(P_predict(1, 1), P_predict_expected(1, 1), 1e-5); - - // Perform update - Eigen::MatrixXd y_t(2, 1); - y_t << 1.05, 2.05; - EXPECT_TRUE(kf_.update(y_t)); - - // Check the updated state and covariance matrix - const Eigen::MatrixXd PCT_t = P_predict_expected * C_t.transpose(); - const Eigen::MatrixXd K_t = PCT_t * ((R_t + C_t * PCT_t).inverse()); - const Eigen::MatrixXd y_pred = C_t * x_predict_expected; - Eigen::MatrixXd x_update_expected = x_predict_expected + K_t * (y_t - y_pred); - Eigen::MatrixXd P_update_expected = P_predict_expected - K_t * (C_t * P_predict_expected); - - Eigen::MatrixXd x_update; - kf_.getX(x_update); - Eigen::MatrixXd P_update; - kf_.getP(P_update); - - EXPECT_NEAR(x_update(0, 0), x_update_expected(0, 0), 1e-5); - EXPECT_NEAR(x_update(1, 0), x_update_expected(1, 0), 1e-5); - EXPECT_NEAR(P_update(0, 0), P_update_expected(0, 0), 1e-5); - EXPECT_NEAR(P_update(1, 1), P_update_expected(1, 1), 1e-5); -} - -int main(int argc, char * argv[]) -{ - testing::InitGoogleTest(&argc, argv); - bool result = RUN_ALL_TESTS(); - return result; -} diff --git a/common/autoware_kalman_filter/test/test_time_delay_kalman_filter.cpp b/common/autoware_kalman_filter/test/test_time_delay_kalman_filter.cpp deleted file mode 100644 index 50c22fae123bc..0000000000000 --- a/common/autoware_kalman_filter/test/test_time_delay_kalman_filter.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2023 The Autoware Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "autoware/kalman_filter/time_delay_kalman_filter.hpp" - -#include - -using autoware::kalman_filter::TimeDelayKalmanFilter; - -TEST(time_delay_kalman_filter, td_kf) -{ - TimeDelayKalmanFilter td_kf_; - - Eigen::MatrixXd x_t(3, 1); - x_t << 1.0, 2.0, 3.0; - Eigen::MatrixXd P_t(3, 3); - P_t << 0.1, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.3; - const int max_delay_step = 5; - const int dim_x = x_t.rows(); - const int dim_x_ex = dim_x * max_delay_step; - // Initialize the filter - td_kf_.init(x_t, P_t, max_delay_step); - - // Check if initialization was successful - Eigen::MatrixXd x_init = td_kf_.getLatestX(); - Eigen::MatrixXd P_init = td_kf_.getLatestP(); - Eigen::MatrixXd x_ex_t = Eigen::MatrixXd::Zero(dim_x_ex, 1); - Eigen::MatrixXd P_ex_t = Eigen::MatrixXd::Zero(dim_x_ex, dim_x_ex); - for (int i = 0; i < max_delay_step; ++i) { - x_ex_t.block(i * dim_x, 0, dim_x, 1) = x_t; - P_ex_t.block(i * dim_x, i * dim_x, dim_x, dim_x) = P_t; - } - - EXPECT_EQ(x_init.rows(), 3); - EXPECT_EQ(x_init.cols(), 1); - EXPECT_EQ(P_init.rows(), 3); - EXPECT_EQ(P_init.cols(), 3); - EXPECT_NEAR(x_init(0, 0), x_t(0, 0), 1e-5); - EXPECT_NEAR(x_init(1, 0), x_t(1, 0), 1e-5); - EXPECT_NEAR(x_init(2, 0), x_t(2, 0), 1e-5); - EXPECT_NEAR(P_init(0, 0), P_t(0, 0), 1e-5); - EXPECT_NEAR(P_init(1, 1), P_t(1, 1), 1e-5); - EXPECT_NEAR(P_init(2, 2), P_t(2, 2), 1e-5); - - // Define prediction parameters - Eigen::MatrixXd A_t(3, 3); - A_t << 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0; - Eigen::MatrixXd Q_t(3, 3); - Q_t << 0.01, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.03; - Eigen::MatrixXd x_next(3, 1); - x_next << 2.0, 4.0, 6.0; - - // Perform prediction - EXPECT_TRUE(td_kf_.predictWithDelay(x_next, A_t, Q_t)); - - // Check the prediction state and covariance matrix - Eigen::MatrixXd x_predict = td_kf_.getLatestX(); - Eigen::MatrixXd P_predict = td_kf_.getLatestP(); - Eigen::MatrixXd x_tmp = Eigen::MatrixXd::Zero(dim_x_ex, 1); - x_tmp.block(0, 0, dim_x, 1) = A_t * x_t; - x_tmp.block(dim_x, 0, dim_x_ex - dim_x, 1) = x_ex_t.block(0, 0, dim_x_ex - dim_x, 1); - x_ex_t = x_tmp; - Eigen::MatrixXd x_predict_expected = x_ex_t.block(0, 0, dim_x, 1); - Eigen::MatrixXd P_tmp = Eigen::MatrixXd::Zero(dim_x_ex, dim_x_ex); - P_tmp.block(0, 0, dim_x, dim_x) = A_t * P_ex_t.block(0, 0, dim_x, dim_x) * A_t.transpose() + Q_t; - P_tmp.block(0, dim_x, dim_x, dim_x_ex - dim_x) = - A_t * P_ex_t.block(0, 0, dim_x, dim_x_ex - dim_x); - P_tmp.block(dim_x, 0, dim_x_ex - dim_x, dim_x) = - P_ex_t.block(0, 0, dim_x_ex - dim_x, dim_x) * A_t.transpose(); - P_tmp.block(dim_x, dim_x, dim_x_ex - dim_x, dim_x_ex - dim_x) = - P_ex_t.block(0, 0, dim_x_ex - dim_x, dim_x_ex - dim_x); - P_ex_t = P_tmp; - Eigen::MatrixXd P_predict_expected = P_ex_t.block(0, 0, dim_x, dim_x); - EXPECT_NEAR(x_predict(0, 0), x_predict_expected(0, 0), 1e-5); - EXPECT_NEAR(x_predict(1, 0), x_predict_expected(1, 0), 1e-5); - EXPECT_NEAR(x_predict(2, 0), x_predict_expected(2, 0), 1e-5); - EXPECT_NEAR(P_predict(0, 0), P_predict_expected(0, 0), 1e-5); - EXPECT_NEAR(P_predict(1, 1), P_predict_expected(1, 1), 1e-5); - EXPECT_NEAR(P_predict(2, 2), P_predict_expected(2, 2), 1e-5); - - // Define update parameters - Eigen::MatrixXd C_t(3, 3); - C_t << 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5; - Eigen::MatrixXd R_t(3, 3); - R_t << 0.001, 0.0, 0.0, 0.0, 0.002, 0.0, 0.0, 0.0, 0.003; - Eigen::MatrixXd y_t(3, 1); - y_t << 1.05, 2.05, 3.05; - const int delay_step = 2; // Choose an appropriate delay step - const int dim_y = y_t.rows(); - - // Perform update - EXPECT_TRUE(td_kf_.updateWithDelay(y_t, C_t, R_t, delay_step)); - - // Check the updated state and covariance matrix - Eigen::MatrixXd x_update = td_kf_.getLatestX(); - Eigen::MatrixXd P_update = td_kf_.getLatestP(); - - Eigen::MatrixXd C_ex_t = Eigen::MatrixXd::Zero(dim_y, dim_x_ex); - const Eigen::MatrixXd PCT_t = P_ex_t * C_ex_t.transpose(); - const Eigen::MatrixXd K_t = PCT_t * ((R_t + C_ex_t * PCT_t).inverse()); - const Eigen::MatrixXd y_pred = C_ex_t * x_ex_t; - x_ex_t = x_ex_t + K_t * (y_t - y_pred); - P_ex_t = P_ex_t - K_t * (C_ex_t * P_ex_t); - Eigen::MatrixXd x_update_expected = x_ex_t.block(0, 0, dim_x, 1); - Eigen::MatrixXd P_update_expected = P_ex_t.block(0, 0, dim_x, dim_x); - EXPECT_NEAR(x_update(0, 0), x_update_expected(0, 0), 1e-5); - EXPECT_NEAR(x_update(1, 0), x_update_expected(1, 0), 1e-5); - EXPECT_NEAR(x_update(2, 0), x_update_expected(2, 0), 1e-5); - EXPECT_NEAR(P_update(0, 0), P_update_expected(0, 0), 1e-5); - EXPECT_NEAR(P_update(1, 1), P_update_expected(1, 1), 1e-5); - EXPECT_NEAR(P_update(2, 2), P_update_expected(2, 2), 1e-5); -} From 7f496888b6ef10eb5ee9e9897505220d92415164 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:18:06 +0900 Subject: [PATCH 22/61] feat(autoware_costmap_generator): tier4_debug_msgs changed to autoware_internal-debug_msgs in autoware_costmap_generator (#9901) feat: tier4_debug_msgs changed to autoware_internal-debug_msgs in files planning/autoware_costmap_generator Signed-off-by: vish0012 --- .../autoware/costmap_generator/costmap_generator.hpp | 5 +++-- .../autoware_costmap_generator/src/costmap_generator.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/planning/autoware_costmap_generator/include/autoware/costmap_generator/costmap_generator.hpp b/planning/autoware_costmap_generator/include/autoware/costmap_generator/costmap_generator.hpp index 4fed5bcb6cff3..b6749117a6177 100644 --- a/planning/autoware_costmap_generator/include/autoware/costmap_generator/costmap_generator.hpp +++ b/planning/autoware_costmap_generator/include/autoware/costmap_generator/costmap_generator.hpp @@ -58,10 +58,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -99,7 +99,8 @@ class CostmapGenerator : public rclcpp::Node rclcpp::Publisher::SharedPtr pub_costmap_; rclcpp::Publisher::SharedPtr pub_occupancy_grid_; rclcpp::Publisher::SharedPtr pub_processing_time_; - rclcpp::Publisher::SharedPtr pub_processing_time_ms_; + rclcpp::Publisher::SharedPtr + pub_processing_time_ms_; rclcpp::Subscription::SharedPtr sub_lanelet_bin_map_; autoware::universe_utils::InterProcessPollingSubscriber diff --git a/planning/autoware_costmap_generator/src/costmap_generator.cpp b/planning/autoware_costmap_generator/src/costmap_generator.cpp index 081a6ead91cda..70b8051bcdc12 100644 --- a/planning/autoware_costmap_generator/src/costmap_generator.cpp +++ b/planning/autoware_costmap_generator/src/costmap_generator.cpp @@ -176,7 +176,8 @@ CostmapGenerator::CostmapGenerator(const rclcpp::NodeOptions & node_options) create_publisher("processing_time", 1); time_keeper_ = std::make_shared(pub_processing_time_); pub_processing_time_ms_ = - this->create_publisher("~/debug/processing_time_ms", 1); + this->create_publisher( + "~/debug/processing_time_ms", 1); // Timer const auto period_ns = rclcpp::Rate(param_->update_rate).period(); @@ -269,7 +270,7 @@ void CostmapGenerator::onTimer() if (!isActive()) { // Publish ProcessingTime - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); pub_processing_time_ms_->publish(processing_time_msg); @@ -485,7 +486,7 @@ void CostmapGenerator::publishCostmap( pub_costmap_->publish(*out_gridmap_msg); // Publish ProcessingTime - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); pub_processing_time_ms_->publish(processing_time_msg); From 9a2ebcc9f1f55f3aa28ad46a6d0b825f52e45cea Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:21:18 +0900 Subject: [PATCH 23/61] feat(autoware_surround_obstacle_checker): tier4_debug_msgs changed to autoware_internal_debug_msgs in autoware_surround_obstacle_checker (#9915) feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files planning/autoware_surround_obstacle_checker Signed-off-by: vish0012 --- planning/autoware_surround_obstacle_checker/src/node.cpp | 6 +++--- planning/autoware_surround_obstacle_checker/src/node.hpp | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/planning/autoware_surround_obstacle_checker/src/node.cpp b/planning/autoware_surround_obstacle_checker/src/node.cpp index 0adca312ca733..b3881a8f4fbd9 100644 --- a/planning/autoware_surround_obstacle_checker/src/node.cpp +++ b/planning/autoware_surround_obstacle_checker/src/node.cpp @@ -81,8 +81,8 @@ SurroundObstacleCheckerNode::SurroundObstacleCheckerNode(const rclcpp::NodeOptio "~/output/velocity_limit_clear_command", rclcpp::QoS{1}.transient_local()); pub_velocity_limit_ = this->create_publisher( "~/output/max_velocity", rclcpp::QoS{1}.transient_local()); - pub_processing_time_ = - this->create_publisher("~/debug/processing_time_ms", 1); + pub_processing_time_ = this->create_publisher( + "~/debug/processing_time_ms", 1); using std::chrono_literals::operator""ms; timer_ = rclcpp::create_timer( @@ -231,7 +231,7 @@ void SurroundObstacleCheckerNode::onTimer() debug_ptr_->pushPose(odometry_ptr_->pose.pose, PoseType::NoStart); } - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); pub_processing_time_->publish(processing_time_msg); diff --git a/planning/autoware_surround_obstacle_checker/src/node.hpp b/planning/autoware_surround_obstacle_checker/src/node.hpp index f84ad3a8f5987..b6d6bffefed1a 100644 --- a/planning/autoware_surround_obstacle_checker/src/node.hpp +++ b/planning/autoware_surround_obstacle_checker/src/node.hpp @@ -24,12 +24,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -106,7 +106,8 @@ class SurroundObstacleCheckerNode : public rclcpp::Node this, "~/input/objects"}; rclcpp::Publisher::SharedPtr pub_clear_velocity_limit_; rclcpp::Publisher::SharedPtr pub_velocity_limit_; - rclcpp::Publisher::SharedPtr pub_processing_time_; + rclcpp::Publisher::SharedPtr + pub_processing_time_; // parameter callback result OnSetParametersCallbackHandle::SharedPtr set_param_res_; From 2028af955d261cc3dfd4836f7501b60a5e030a59 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:23:07 +0900 Subject: [PATCH 24/61] feat(autoware_freespace_planner): tier4_debug_msgs changed to autoware_internal_debug_msgs in autoware_freespace_planner (#9903) feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in flies planning/autoware_freespace_planner Signed-off-by: vish0012 --- .../autoware/freespace_planner/freespace_planner_node.hpp | 5 +++-- .../autoware_freespace_planner/freespace_planner_node.cpp | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/planning/autoware_freespace_planner/include/autoware/freespace_planner/freespace_planner_node.hpp b/planning/autoware_freespace_planner/include/autoware/freespace_planner/freespace_planner_node.hpp index 1f5a52ca040a0..bd431372b70dc 100644 --- a/planning/autoware_freespace_planner/include/autoware/freespace_planner/freespace_planner_node.hpp +++ b/planning/autoware_freespace_planner/include/autoware/freespace_planner/freespace_planner_node.hpp @@ -39,13 +39,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #ifdef ROS_DISTRO_GALACTIC @@ -112,7 +112,8 @@ class FreespacePlannerNode : public rclcpp::Node rclcpp::Publisher::SharedPtr debug_pose_array_pub_; rclcpp::Publisher::SharedPtr debug_partial_pose_array_pub_; rclcpp::Publisher::SharedPtr parking_state_pub_; - rclcpp::Publisher::SharedPtr processing_time_pub_; + rclcpp::Publisher::SharedPtr + processing_time_pub_; rclcpp::Subscription::SharedPtr route_sub_; diff --git a/planning/autoware_freespace_planner/src/autoware_freespace_planner/freespace_planner_node.cpp b/planning/autoware_freespace_planner/src/autoware_freespace_planner/freespace_planner_node.cpp index a937114e653c6..2749408bedb7b 100644 --- a/planning/autoware_freespace_planner/src/autoware_freespace_planner/freespace_planner_node.cpp +++ b/planning/autoware_freespace_planner/src/autoware_freespace_planner/freespace_planner_node.cpp @@ -95,8 +95,8 @@ FreespacePlannerNode::FreespacePlannerNode(const rclcpp::NodeOptions & node_opti debug_pose_array_pub_ = create_publisher("~/debug/pose_array", qos); debug_partial_pose_array_pub_ = create_publisher("~/debug/partial_pose_array", qos); parking_state_pub_ = create_publisher("is_completed", qos); - processing_time_pub_ = - create_publisher("~/debug/processing_time_ms", 1); + processing_time_pub_ = create_publisher( + "~/debug/processing_time_ms", 1); } // TF @@ -362,7 +362,7 @@ void FreespacePlannerNode::onTimer() is_new_parking_cycle_ = false; // Publish ProcessingTime - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); processing_time_pub_->publish(processing_time_msg); From e96b361fc3d6f49bc4b097ca402ffbd3b590bb89 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:24:36 +0900 Subject: [PATCH 25/61] feat(autoware_scenario_selector): tier4_debug_msgs changed to autoware_internal_debug_msgs in autoware_scenario_selector (#9914) feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files planning/autoware_scenario_selector Signed-off-by: vish0012 --- .../include/autoware/scenario_selector/node.hpp | 5 +++-- planning/autoware_scenario_selector/src/node.cpp | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/planning/autoware_scenario_selector/include/autoware/scenario_selector/node.hpp b/planning/autoware_scenario_selector/include/autoware/scenario_selector/node.hpp index 244876ee2cb22..7e215fcfef8dd 100644 --- a/planning/autoware_scenario_selector/include/autoware/scenario_selector/node.hpp +++ b/planning/autoware_scenario_selector/include/autoware/scenario_selector/node.hpp @@ -19,13 +19,13 @@ #include #include +#include #include #include #include #include #include #include -#include #include #include @@ -97,7 +97,8 @@ class ScenarioSelectorNode : public rclcpp::Node rclcpp::Subscription::SharedPtr sub_parking_trajectory_; rclcpp::Publisher::SharedPtr pub_trajectory_; rclcpp::Publisher::SharedPtr pub_scenario_; - rclcpp::Publisher::SharedPtr pub_processing_time_; + rclcpp::Publisher::SharedPtr + pub_processing_time_; // polling subscribers universe_utils::InterProcessPollingSubscriber< diff --git a/planning/autoware_scenario_selector/src/node.cpp b/planning/autoware_scenario_selector/src/node.cpp index defbde4f6aabc..91e86bfea6dba 100644 --- a/planning/autoware_scenario_selector/src/node.cpp +++ b/planning/autoware_scenario_selector/src/node.cpp @@ -390,7 +390,7 @@ void ScenarioSelectorNode::onTimer() pub_scenario_->publish(scenario); // Publish ProcessingTime - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); pub_processing_time_->publish(processing_time_msg); @@ -490,8 +490,8 @@ ScenarioSelectorNode::ScenarioSelectorNode(const rclcpp::NodeOptions & node_opti this, get_clock(), period_ns, std::bind(&ScenarioSelectorNode::onTimer, this)); published_time_publisher_ = std::make_unique(this); - pub_processing_time_ = - this->create_publisher("~/debug/processing_time_ms", 1); + pub_processing_time_ = this->create_publisher( + "~/debug/processing_time_ms", 1); } } // namespace autoware::scenario_selector From 9b8b3fc3280a678ea0205009339c587b5febf096 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:44:22 +0900 Subject: [PATCH 26/61] =?UTF-8?q?feat(autoware=5Foccupancy=5Fgrid=5Fmap=5F?= =?UTF-8?q?outlier=5Ffilter):=20tier4=5Fdebug=5Fmsgs=20changed=20to=20auto?= =?UTF-8?q?ware=5Finternal=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(#9894)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files perception/autoware_occupancy_grid_map_outlier_filter Signed-off-by: vish0012 Co-authored-by: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> --- .../src/occupancy_grid_map_outlier_filter_node.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perception/autoware_occupancy_grid_map_outlier_filter/src/occupancy_grid_map_outlier_filter_node.cpp b/perception/autoware_occupancy_grid_map_outlier_filter/src/occupancy_grid_map_outlier_filter_node.cpp index eb52b903b90ca..094825056e62c 100644 --- a/perception/autoware_occupancy_grid_map_outlier_filter/src/occupancy_grid_map_outlier_filter_node.cpp +++ b/perception/autoware_occupancy_grid_map_outlier_filter/src/occupancy_grid_map_outlier_filter_node.cpp @@ -420,9 +420,9 @@ void OccupancyGridMapOutlierFilterComponent::onOccupancyGridMapAndPointCloud2( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } From b7ce209a911eac03593240b8b42676b688991626 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:47:29 +0900 Subject: [PATCH 27/61] =?UTF-8?q?feat(autoware=5Flidar=5Fapollo=5Finstance?= =?UTF-8?q?=5Fsegmentation):=20tier4=5Fdebug=5Fmsgs=20to=20autoware=5Finte?= =?UTF-8?q?rnal=5Fdebug=5Fmsgs=20in=20files=20perce=E2=80=A6=20(#9876)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs to autoware_internal_debug_msgs in files perception/autoware_lidar_apollo_instance_segmentation Signed-off-by: vish0012 Co-authored-by: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> --- .../CMakeLists.txt | 4 ++-- .../autoware_lidar_apollo_instance_segmentation/package.xml | 2 +- .../autoware_lidar_apollo_instance_segmentation/src/node.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/perception/autoware_lidar_apollo_instance_segmentation/CMakeLists.txt b/perception/autoware_lidar_apollo_instance_segmentation/CMakeLists.txt index 16ab7ecccae60..0555cedc235d9 100644 --- a/perception/autoware_lidar_apollo_instance_segmentation/CMakeLists.txt +++ b/perception/autoware_lidar_apollo_instance_segmentation/CMakeLists.txt @@ -9,7 +9,7 @@ find_package(rclcpp REQUIRED) find_package(rclcpp_components REQUIRED) find_package(tf2_eigen REQUIRED) find_package(autoware_universe_utils REQUIRED) -find_package(tier4_debug_msgs REQUIRED) +find_package(autoware_internal_debug_msgs REQUIRED) find_package(tier4_perception_msgs REQUIRED) find_package(autoware_tensorrt_common) @@ -50,7 +50,7 @@ target_link_libraries(${PROJECT_NAME} rclcpp_components::component tf2_eigen::tf2_eigen ${autoware_tensorrt_common_TARGETS} - ${tier4_debug_msgs_TARGETS} + ${autoware_internal_debug_msgs_TARGETS} ${tier4_perception_msgs_TARGETS} ) diff --git a/perception/autoware_lidar_apollo_instance_segmentation/package.xml b/perception/autoware_lidar_apollo_instance_segmentation/package.xml index 8a3d5a7ea6f76..8ff7ce77d943d 100755 --- a/perception/autoware_lidar_apollo_instance_segmentation/package.xml +++ b/perception/autoware_lidar_apollo_instance_segmentation/package.xml @@ -14,6 +14,7 @@ ament_cmake autoware_cuda_utils + autoware_internal_debug_msgs autoware_perception_msgs autoware_tensorrt_common autoware_universe_utils @@ -22,7 +23,6 @@ rclcpp rclcpp_components tf2_eigen - tier4_debug_msgs tier4_perception_msgs ament_lint_auto diff --git a/perception/autoware_lidar_apollo_instance_segmentation/src/node.cpp b/perception/autoware_lidar_apollo_instance_segmentation/src/node.cpp index 9a3e13b81120f..c535fc6762e1f 100644 --- a/perception/autoware_lidar_apollo_instance_segmentation/src/node.cpp +++ b/perception/autoware_lidar_apollo_instance_segmentation/src/node.cpp @@ -62,9 +62,9 @@ void LidarInstanceSegmentationNode::pointCloudCallback( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } From acaa40c95a109e21687fe7f2e7f4b37f2ebb1d6b Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:50:03 +0900 Subject: [PATCH 28/61] =?UTF-8?q?feat(autoware=5Fground=5Fsegmentation):?= =?UTF-8?q?=20tier4=5Fdebug=5Fmsgs=20changed=20to=20autoware=5Finternal=5F?= =?UTF-8?q?debug=5Fmsgs=20in=20fil=E2=80=A6=20(#9878)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files perception/autoware_ground_segmentation Signed-off-by: vish0012 --- .../src/scan_ground_filter/node.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perception/autoware_ground_segmentation/src/scan_ground_filter/node.cpp b/perception/autoware_ground_segmentation/src/scan_ground_filter/node.cpp index 74b4edbe595ea..8fda0c1395caf 100644 --- a/perception/autoware_ground_segmentation/src/scan_ground_filter/node.cpp +++ b/perception/autoware_ground_segmentation/src/scan_ground_filter/node.cpp @@ -369,9 +369,9 @@ void ScanGroundFilterComponent::faster_filter( if (debug_publisher_ptr_ && stop_watch_ptr_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/processing_time_ms", processing_time_ms); } } From b65e042ebd1df00a09d6a47648dfb07df3e0f68a Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:50:22 +0900 Subject: [PATCH 29/61] feat(autoware_image_diagnostics): tier4_debug_msgs changed to autoware_internal_debug_msgs in autoware_image_diagnostics (#9918) feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files sensing/autoware_image_diagnostics Signed-off-by: vish0012 --- sensing/autoware_image_diagnostics/README.md | 14 +++++++------- sensing/autoware_image_diagnostics/package.xml | 2 +- .../src/image_diagnostics_node.cpp | 4 ++-- .../src/image_diagnostics_node.hpp | 11 ++++++----- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/sensing/autoware_image_diagnostics/README.md b/sensing/autoware_image_diagnostics/README.md index 03858088564b3..42fcbdc8dc612 100644 --- a/sensing/autoware_image_diagnostics/README.md +++ b/sensing/autoware_image_diagnostics/README.md @@ -28,13 +28,13 @@ After all image's blocks state are evaluated, the whole image status is summariz ### Output -| Name | Type | Description | -| ----------------------------------- | --------------------------------------- | ------------------------------------- | -| `image_diag/debug/gray_image` | `sensor_msgs::msg::Image` | gray image | -| `image_diag/debug/dft_image` | `sensor_msgs::msg::Image` | discrete Fourier transformation image | -| `image_diag/debug/diag_block_image` | `sensor_msgs::msg::Image` | each block state colorization | -| `image_diag/image_state_diag` | `tier4_debug_msgs::msg::Int32Stamped` | image diagnostics status value | -| `/diagnostics` | `diagnostic_msgs::msg::DiagnosticArray` | diagnostics | +| Name | Type | Description | +| ----------------------------------- | ------------------------------------------------- | ------------------------------------- | +| `image_diag/debug/gray_image` | `sensor_msgs::msg::Image` | gray image | +| `image_diag/debug/dft_image` | `sensor_msgs::msg::Image` | discrete Fourier transformation image | +| `image_diag/debug/diag_block_image` | `sensor_msgs::msg::Image` | each block state colorization | +| `image_diag/image_state_diag` | `autoware_internal_debug_msgs::msg::Int32Stamped` | image diagnostics status value | +| `/diagnostics` | `diagnostic_msgs::msg::DiagnosticArray` | diagnostics | ## Parameters diff --git a/sensing/autoware_image_diagnostics/package.xml b/sensing/autoware_image_diagnostics/package.xml index 2e4556de2b92b..3140b87e1f1b9 100644 --- a/sensing/autoware_image_diagnostics/package.xml +++ b/sensing/autoware_image_diagnostics/package.xml @@ -12,6 +12,7 @@ ament_cmake_auto + autoware_internal_debug_msgs autoware_universe_utils cv_bridge diagnostic_updater @@ -19,7 +20,6 @@ rclcpp rclcpp_components sensor_msgs - tier4_debug_msgs ament_lint_auto autoware_lint_common diff --git a/sensing/autoware_image_diagnostics/src/image_diagnostics_node.cpp b/sensing/autoware_image_diagnostics/src/image_diagnostics_node.cpp index 1625cba5b72aa..57e53aee46328 100644 --- a/sensing/autoware_image_diagnostics/src/image_diagnostics_node.cpp +++ b/sensing/autoware_image_diagnostics/src/image_diagnostics_node.cpp @@ -33,7 +33,7 @@ ImageDiagNode::ImageDiagNode(const rclcpp::NodeOptions & node_options) dft_image_pub_ = image_transport::create_publisher(this, "image_diag/debug/dft_image"); gray_image_pub_ = image_transport::create_publisher(this, "image_diag/debug/gray_image"); - image_state_pub_ = create_publisher( + image_state_pub_ = create_publisher( "image_diag/image_state_diag", rclcpp::SensorDataQoS()); updater_.setHardwareID("Image_Diagnostics"); @@ -225,7 +225,7 @@ void ImageDiagNode::ImageChecker(const sensor_msgs::msg::Image::ConstSharedPtr i } else { params_.diagnostic_status = 0; } - tier4_debug_msgs::msg::Int32Stamped image_state_out; + autoware_internal_debug_msgs::msg::Int32Stamped image_state_out; image_state_out.data = params_.diagnostic_status; image_state_pub_->publish(image_state_out); diff --git a/sensing/autoware_image_diagnostics/src/image_diagnostics_node.hpp b/sensing/autoware_image_diagnostics/src/image_diagnostics_node.hpp index 325624062b90b..9383da33160f9 100644 --- a/sensing/autoware_image_diagnostics/src/image_diagnostics_node.hpp +++ b/sensing/autoware_image_diagnostics/src/image_diagnostics_node.hpp @@ -21,10 +21,10 @@ #include #include +#include +#include +#include #include -#include -#include -#include #if __has_include() #include @@ -95,8 +95,9 @@ class ImageDiagNode : public rclcpp::Node image_transport::Publisher block_diag_image_pub_; image_transport::Publisher dft_image_pub_; image_transport::Publisher gray_image_pub_; - rclcpp::Publisher::SharedPtr average_pub_; - rclcpp::Publisher::SharedPtr image_state_pub_; + rclcpp::Publisher::SharedPtr + average_pub_; + rclcpp::Publisher::SharedPtr image_state_pub_; }; } // namespace autoware::image_diagnostics From 221a7bc0eb333f27638d5bdc5a9d7ecc4fd79be0 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:50:56 +0900 Subject: [PATCH 30/61] =?UTF-8?q?feat(autoware=5Fcompare=5Fmap=5Fsegmentat?= =?UTF-8?q?ion):=20tier4=5Fdebug=5Fmsgs=20changed=20to=20autoware=5Fintern?= =?UTF-8?q?al=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(#9869)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files perception/autoware_compare_map_segmentation Signed-off-by: vish0012 Co-authored-by: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> --- .../src/distance_based_compare_map_filter/node.cpp | 4 ++-- .../src/voxel_based_approximate_compare_map_filter/node.cpp | 4 ++-- .../src/voxel_based_compare_map_filter/node.cpp | 4 ++-- .../src/voxel_distance_based_compare_map_filter/node.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/perception/autoware_compare_map_segmentation/src/distance_based_compare_map_filter/node.cpp b/perception/autoware_compare_map_segmentation/src/distance_based_compare_map_filter/node.cpp index ae07d54ad53d6..ac759504de557 100644 --- a/perception/autoware_compare_map_segmentation/src/distance_based_compare_map_filter/node.cpp +++ b/perception/autoware_compare_map_segmentation/src/distance_based_compare_map_filter/node.cpp @@ -173,9 +173,9 @@ void DistanceBasedCompareMapFilterComponent::filter( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } diff --git a/perception/autoware_compare_map_segmentation/src/voxel_based_approximate_compare_map_filter/node.cpp b/perception/autoware_compare_map_segmentation/src/voxel_based_approximate_compare_map_filter/node.cpp index 9f325b36676be..5794cfe37a45b 100644 --- a/perception/autoware_compare_map_segmentation/src/voxel_based_approximate_compare_map_filter/node.cpp +++ b/perception/autoware_compare_map_segmentation/src/voxel_based_approximate_compare_map_filter/node.cpp @@ -141,9 +141,9 @@ void VoxelBasedApproximateCompareMapFilterComponent::filter( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } diff --git a/perception/autoware_compare_map_segmentation/src/voxel_based_compare_map_filter/node.cpp b/perception/autoware_compare_map_segmentation/src/voxel_based_compare_map_filter/node.cpp index a31d5ec5dd6d6..db5e46a0eff5a 100644 --- a/perception/autoware_compare_map_segmentation/src/voxel_based_compare_map_filter/node.cpp +++ b/perception/autoware_compare_map_segmentation/src/voxel_based_compare_map_filter/node.cpp @@ -100,9 +100,9 @@ void VoxelBasedCompareMapFilterComponent::filter( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } diff --git a/perception/autoware_compare_map_segmentation/src/voxel_distance_based_compare_map_filter/node.cpp b/perception/autoware_compare_map_segmentation/src/voxel_distance_based_compare_map_filter/node.cpp index d0bcf381cd62f..775a931ac4c4c 100644 --- a/perception/autoware_compare_map_segmentation/src/voxel_distance_based_compare_map_filter/node.cpp +++ b/perception/autoware_compare_map_segmentation/src/voxel_distance_based_compare_map_filter/node.cpp @@ -173,9 +173,9 @@ void VoxelDistanceBasedCompareMapFilterComponent::filter( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } From cee6ef912154312c3a4e6eff3ee04013cb9d7175 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:54:14 +0900 Subject: [PATCH 31/61] feat(autoware_probabilistic_occupancy_grid_map): tier4_debug_msgs changed to autoware_internal_debug_msgs in autoware_probabilistic_occupancy_grid_map (#9895) feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files perception/autoware_probabilistic_occupancy_grid_map Signed-off-by: vish0012 Co-authored-by: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> --- .../src/fusion/synchronized_grid_map_fusion_node.cpp | 6 +++--- .../pointcloud_based_occupancy_grid_map_node.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/perception/autoware_probabilistic_occupancy_grid_map/src/fusion/synchronized_grid_map_fusion_node.cpp b/perception/autoware_probabilistic_occupancy_grid_map/src/fusion/synchronized_grid_map_fusion_node.cpp index 880dfda03c495..7cde04ca9614b 100644 --- a/perception/autoware_probabilistic_occupancy_grid_map/src/fusion/synchronized_grid_map_fusion_node.cpp +++ b/perception/autoware_probabilistic_occupancy_grid_map/src/fusion/synchronized_grid_map_fusion_node.cpp @@ -332,11 +332,11 @@ void GridMapFusionNode::publish() std::chrono::duration( std::chrono::nanoseconds((this->get_clock()->now() - latest_stamp).nanoseconds())) .count(); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/processing_time_ms", processing_time_ms); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/pipeline_latency_ms", pipeline_latency_ms); } } diff --git a/perception/autoware_probabilistic_occupancy_grid_map/src/pointcloud_based_occupancy_grid_map/pointcloud_based_occupancy_grid_map_node.cpp b/perception/autoware_probabilistic_occupancy_grid_map/src/pointcloud_based_occupancy_grid_map/pointcloud_based_occupancy_grid_map_node.cpp index 4d442ad2c33db..ff836a1ddf760 100644 --- a/perception/autoware_probabilistic_occupancy_grid_map/src/pointcloud_based_occupancy_grid_map/pointcloud_based_occupancy_grid_map_node.cpp +++ b/perception/autoware_probabilistic_occupancy_grid_map/src/pointcloud_based_occupancy_grid_map/pointcloud_based_occupancy_grid_map_node.cpp @@ -261,11 +261,11 @@ void PointcloudBasedOccupancyGridMapNode::onPointcloudWithObstacleAndRaw( std::chrono::nanoseconds( (this->get_clock()->now() - input_raw_msg->header.stamp).nanoseconds())) .count(); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/processing_time_ms", processing_time_ms); - debug_publisher_ptr_->publish( + debug_publisher_ptr_->publish( "debug/pipeline_latency_ms", pipeline_latency_ms); } } From 95e7939e7e3b6164913ce5b5119247de94a89ac8 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:06:17 +0900 Subject: [PATCH 32/61] feat(autoware_pointcloud_preprocessor): tier4_debug_msgs changed to autoware_internal_debug_msgs in autoware_pointcloud_preprocessor (#9920) feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files sensing/autoware_pointcloud_preprocessor Signed-off-by: vish0012 --- .../docs/blockage-diag.md | 20 +++++++++---------- .../docs/dual-return-outlier-filter.md | 10 +++++----- .../blockage_diag/blockage_diag_node.hpp | 13 +++++++----- .../concatenate_and_time_sync_nodelet.hpp | 4 ++-- .../concatenate_pointclouds.hpp | 4 ++-- .../dual_return_outlier_filter_node.hpp | 4 ++-- .../ring_outlier_filter_node.hpp | 2 +- .../time_synchronizer_node.hpp | 4 ++-- .../package.xml | 2 +- .../src/blockage_diag/blockage_diag_node.cpp | 12 +++++------ .../concatenate_and_time_sync_nodelet.cpp | 6 +++--- .../concatenate_pointclouds.cpp | 6 +++--- .../crop_box_filter/crop_box_filter_node.cpp | 6 +++--- .../distortion_corrector_node.cpp | 6 +++--- ...ased_voxel_grid_downsample_filter_node.cpp | 6 +++--- .../dual_return_outlier_filter_node.cpp | 4 ++-- .../ring_outlier_filter_node.cpp | 10 +++++----- .../time_synchronizer_node.cpp | 6 +++--- 18 files changed, 64 insertions(+), 61 deletions(-) diff --git a/sensing/autoware_pointcloud_preprocessor/docs/blockage-diag.md b/sensing/autoware_pointcloud_preprocessor/docs/blockage-diag.md index 911cda3823021..a9dcb8437ec67 100644 --- a/sensing/autoware_pointcloud_preprocessor/docs/blockage-diag.md +++ b/sensing/autoware_pointcloud_preprocessor/docs/blockage-diag.md @@ -38,16 +38,16 @@ This implementation inherits `autoware::pointcloud_preprocessor::Filter` class, ### Output -| Name | Type | Description | -| :-------------------------------------------------------- | :-------------------------------------- | ------------------------------------------------------------------------------------------------ | -| `~/output/blockage_diag/debug/blockage_mask_image` | `sensor_msgs::msg::Image` | The mask image of detected blockage | -| `~/output/blockage_diag/debug/ground_blockage_ratio` | `tier4_debug_msgs::msg::Float32Stamped` | The area ratio of blockage region in ground region | -| `~/output/blockage_diag/debug/sky_blockage_ratio` | `tier4_debug_msgs::msg::Float32Stamped` | The area ratio of blockage region in sky region | -| `~/output/blockage_diag/debug/lidar_depth_map` | `sensor_msgs::msg::Image` | The depth map image of input point cloud | -| `~/output/blockage_diag/debug/single_frame_dust_mask` | `sensor_msgs::msg::Image` | The mask image of detected dusty area in latest single frame | -| `~/output/blockage_diag/debug/multi_frame_dust_mask` | `sensor_msgs::msg::Image` | The mask image of continuous detected dusty area | -| `~/output/blockage_diag/debug/blockage_dust_merged_image` | `sensor_msgs::msg::Image` | The merged image of blockage detection(red) and multi frame dusty area detection(yellow) results | -| `~/output/blockage_diag/debug/ground_dust_ratio` | `tier4_debug_msgs::msg::Float32Stamped` | The ratio of dusty area divided by area where ray usually returns from the ground. | +| Name | Type | Description | +| :-------------------------------------------------------- | :-------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `~/output/blockage_diag/debug/blockage_mask_image` | `sensor_msgs::msg::Image` | The mask image of detected blockage | +| `~/output/blockage_diag/debug/ground_blockage_ratio` | `autoware_internal_debug_msgs::msg::Float32Stamped` | The area ratio of blockage region in ground region | +| `~/output/blockage_diag/debug/sky_blockage_ratio` | `autoware_internal_debug_msgs::msg::Float32Stamped` | The area ratio of blockage region in sky region | +| `~/output/blockage_diag/debug/lidar_depth_map` | `sensor_msgs::msg::Image` | The depth map image of input point cloud | +| `~/output/blockage_diag/debug/single_frame_dust_mask` | `sensor_msgs::msg::Image` | The mask image of detected dusty area in latest single frame | +| `~/output/blockage_diag/debug/multi_frame_dust_mask` | `sensor_msgs::msg::Image` | The mask image of continuous detected dusty area | +| `~/output/blockage_diag/debug/blockage_dust_merged_image` | `sensor_msgs::msg::Image` | The merged image of blockage detection(red) and multi frame dusty area detection(yellow) results | +| `~/output/blockage_diag/debug/ground_dust_ratio` | `autoware_internal_debug_msgs::msg::Float32Stamped` | The ratio of dusty area divided by area where ray usually returns from the ground. | ## Parameters diff --git a/sensing/autoware_pointcloud_preprocessor/docs/dual-return-outlier-filter.md b/sensing/autoware_pointcloud_preprocessor/docs/dual-return-outlier-filter.md index 8f4da273861a3..0d0423d40ab83 100644 --- a/sensing/autoware_pointcloud_preprocessor/docs/dual-return-outlier-filter.md +++ b/sensing/autoware_pointcloud_preprocessor/docs/dual-return-outlier-filter.md @@ -36,11 +36,11 @@ This implementation inherits `autoware::pointcloud_preprocessor::Filter` class, ### Output -| Name | Type | Description | -| ---------------------------------------------- | --------------------------------------- | ------------------------------------------------------- | -| `/dual_return_outlier_filter/frequency_image` | `sensor_msgs::msg::Image` | The histogram image that represent visibility | -| `/dual_return_outlier_filter/visibility` | `tier4_debug_msgs::msg::Float32Stamped` | A representation of visibility with a value from 0 to 1 | -| `/dual_return_outlier_filter/pointcloud_noise` | `sensor_msgs::msg::Pointcloud2` | The pointcloud removed as noise | +| Name | Type | Description | +| ---------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------- | +| `/dual_return_outlier_filter/frequency_image` | `sensor_msgs::msg::Image` | The histogram image that represent visibility | +| `/dual_return_outlier_filter/visibility` | `autoware_internal_debug_msgs::msg::Float32Stamped` | A representation of visibility with a value from 0 to 1 | +| `/dual_return_outlier_filter/pointcloud_noise` | `sensor_msgs::msg::Pointcloud2` | The pointcloud removed as noise | ## Parameters diff --git a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/blockage_diag/blockage_diag_node.hpp b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/blockage_diag/blockage_diag_node.hpp index 3601b492c4fe3..2dbda770f6cec 100644 --- a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/blockage_diag/blockage_diag_node.hpp +++ b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/blockage_diag/blockage_diag_node.hpp @@ -22,10 +22,10 @@ #include #include +#include #include #include #include -#include #if __has_include() #include @@ -58,10 +58,13 @@ class BlockageDiagComponent : public autoware::pointcloud_preprocessor::Filter image_transport::Publisher single_frame_dust_mask_pub; image_transport::Publisher multi_frame_dust_mask_pub; image_transport::Publisher blockage_dust_merged_pub; - rclcpp::Publisher::SharedPtr ground_blockage_ratio_pub_; - rclcpp::Publisher::SharedPtr sky_blockage_ratio_pub_; - rclcpp::Publisher::SharedPtr ground_dust_ratio_pub_; - rclcpp::Publisher::SharedPtr blockage_type_pub_; + rclcpp::Publisher::SharedPtr + ground_blockage_ratio_pub_; + rclcpp::Publisher::SharedPtr + sky_blockage_ratio_pub_; + rclcpp::Publisher::SharedPtr + ground_dust_ratio_pub_; + rclcpp::Publisher::SharedPtr blockage_type_pub_; private: void onBlockageChecker(DiagnosticStatusWrapper & stat); diff --git a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_and_time_sync_nodelet.hpp b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_and_time_sync_nodelet.hpp index 40adad3521f8d..6164e85c35717 100644 --- a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_and_time_sync_nodelet.hpp +++ b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_and_time_sync_nodelet.hpp @@ -69,14 +69,14 @@ #include #include +#include +#include #include #include #include #include #include #include -#include -#include #include #include diff --git a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_pointclouds.hpp b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_pointclouds.hpp index 0e959eedae1b6..d57e44431a8d2 100644 --- a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_pointclouds.hpp +++ b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/concatenate_data/concatenate_pointclouds.hpp @@ -68,13 +68,13 @@ #include #include +#include +#include #include #include #include #include #include -#include -#include #include #include diff --git a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/dual_return_outlier_filter_node.hpp b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/dual_return_outlier_filter_node.hpp index ef33e88ef5c98..fa55222fb6530 100644 --- a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/dual_return_outlier_filter_node.hpp +++ b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/dual_return_outlier_filter_node.hpp @@ -22,9 +22,9 @@ #include #include +#include #include #include -#include #if __has_include() #include @@ -54,7 +54,7 @@ class DualReturnOutlierFilterComponent : public autoware::pointcloud_preprocesso /** \brief Parameter service callback */ rcl_interfaces::msg::SetParametersResult paramCallback(const std::vector & p); image_transport::Publisher image_pub_; - rclcpp::Publisher::SharedPtr visibility_pub_; + rclcpp::Publisher::SharedPtr visibility_pub_; rclcpp::Publisher::SharedPtr noise_cloud_pub_; private: diff --git a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_node.hpp b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_node.hpp index c898cbacf33ea..96bd2fb2411a0 100644 --- a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_node.hpp +++ b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_node.hpp @@ -53,7 +53,7 @@ class RingOutlierFilterComponent : public autoware::pointcloud_preprocessor::Fil const PointCloud2ConstPtr & input, const IndicesPtr & indices, PointCloud2 & output, const TransformInfo & transform_info) override; - rclcpp::Publisher::SharedPtr visibility_pub_; + rclcpp::Publisher::SharedPtr visibility_pub_; private: /** \brief publisher of excluded pointcloud for debug reason. **/ diff --git a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/time_synchronizer/time_synchronizer_node.hpp b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/time_synchronizer/time_synchronizer_node.hpp index d36fcb36a7be1..f4921be66a7e2 100644 --- a/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/time_synchronizer/time_synchronizer_node.hpp +++ b/sensing/autoware_pointcloud_preprocessor/include/autoware/pointcloud_preprocessor/time_synchronizer/time_synchronizer_node.hpp @@ -68,14 +68,14 @@ #include #include +#include +#include #include #include #include #include #include #include -#include -#include #include #include diff --git a/sensing/autoware_pointcloud_preprocessor/package.xml b/sensing/autoware_pointcloud_preprocessor/package.xml index 4511c5497a3a0..525b1f3eb0699 100644 --- a/sensing/autoware_pointcloud_preprocessor/package.xml +++ b/sensing/autoware_pointcloud_preprocessor/package.xml @@ -26,6 +26,7 @@ ament_cmake_auto autoware_cmake + autoware_internal_debug_msgs autoware_lanelet2_extension autoware_pcl_extensions autoware_point_types @@ -51,7 +52,6 @@ tf2_eigen tf2_geometry_msgs tf2_ros - tier4_debug_msgs ament_lint_auto autoware_lint_common diff --git a/sensing/autoware_pointcloud_preprocessor/src/blockage_diag/blockage_diag_node.cpp b/sensing/autoware_pointcloud_preprocessor/src/blockage_diag/blockage_diag_node.cpp index 5021a3551c939..e05d5f789f680 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/blockage_diag/blockage_diag_node.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/blockage_diag/blockage_diag_node.cpp @@ -68,7 +68,7 @@ BlockageDiagComponent::BlockageDiagComponent(const rclcpp::NodeOptions & options std::string(this->get_namespace()) + ": dust_validation", this, &BlockageDiagComponent::dustChecker); - ground_dust_ratio_pub_ = create_publisher( + ground_dust_ratio_pub_ = create_publisher( "blockage_diag/debug/ground_dust_ratio", rclcpp::SensorDataQoS()); if (publish_debug_image_) { single_frame_dust_mask_pub = @@ -86,9 +86,9 @@ BlockageDiagComponent::BlockageDiagComponent(const rclcpp::NodeOptions & options blockage_mask_pub_ = image_transport::create_publisher(this, "blockage_diag/debug/blockage_mask_image"); } - ground_blockage_ratio_pub_ = create_publisher( + ground_blockage_ratio_pub_ = create_publisher( "blockage_diag/debug/ground_blockage_ratio", rclcpp::SensorDataQoS()); - sky_blockage_ratio_pub_ = create_publisher( + sky_blockage_ratio_pub_ = create_publisher( "blockage_diag/debug/sky_blockage_ratio", rclcpp::SensorDataQoS()); using std::placeholders::_1; set_param_res_ = this->add_on_set_parameters_callback( @@ -315,7 +315,7 @@ void BlockageDiagComponent::filter( cv::Mat ground_mask(cv::Size(ideal_horizontal_bins, horizontal_ring_id_), CV_8UC1); cv::vconcat(sky_blank, single_dust_ground_img, single_dust_img); - tier4_debug_msgs::msg::Float32Stamped ground_dust_ratio_msg; + autoware_internal_debug_msgs::msg::Float32Stamped ground_dust_ratio_msg; ground_dust_ratio_ = static_cast(cv::countNonZero(single_dust_ground_img)) / (single_dust_ground_img.cols * single_dust_ground_img.rows); ground_dust_ratio_msg.data = ground_dust_ratio_; @@ -386,12 +386,12 @@ void BlockageDiagComponent::filter( } } - tier4_debug_msgs::msg::Float32Stamped ground_blockage_ratio_msg; + autoware_internal_debug_msgs::msg::Float32Stamped ground_blockage_ratio_msg; ground_blockage_ratio_msg.data = ground_blockage_ratio_; ground_blockage_ratio_msg.stamp = now(); ground_blockage_ratio_pub_->publish(ground_blockage_ratio_msg); - tier4_debug_msgs::msg::Float32Stamped sky_blockage_ratio_msg; + autoware_internal_debug_msgs::msg::Float32Stamped sky_blockage_ratio_msg; sky_blockage_ratio_msg.data = sky_blockage_ratio_; sky_blockage_ratio_msg.stamp = now(); sky_blockage_ratio_pub_->publish(sky_blockage_ratio_msg); diff --git a/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_and_time_sync_nodelet.cpp b/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_and_time_sync_nodelet.cpp index f8baae3405873..b49e21b8f30be 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_and_time_sync_nodelet.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_and_time_sync_nodelet.cpp @@ -455,9 +455,9 @@ void PointCloudConcatenateDataSynchronizerComponent::publish() if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } for (const auto & e : cloud_stdmap_) { @@ -468,7 +468,7 @@ void PointCloudConcatenateDataSynchronizerComponent::publish() std::chrono::nanoseconds( (this->get_clock()->now() - e.second->header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug" + e.first + "/pipeline_latency_ms", pipeline_latency_ms); } } diff --git a/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_pointclouds.cpp b/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_pointclouds.cpp index ba29389b88bf7..ba5e2eb51997a 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_pointclouds.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/concatenate_data/concatenate_pointclouds.cpp @@ -271,7 +271,7 @@ void PointCloudConcatenationComponent::publish() std::chrono::nanoseconds( (this->get_clock()->now() - e.second->header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug" + e.first + "/pipeline_latency_ms", pipeline_latency_ms); } } @@ -297,9 +297,9 @@ void PointCloudConcatenationComponent::publish() if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } diff --git a/sensing/autoware_pointcloud_preprocessor/src/crop_box_filter/crop_box_filter_node.cpp b/sensing/autoware_pointcloud_preprocessor/src/crop_box_filter/crop_box_filter_node.cpp index ecbc5b8fd13ef..54c940d414db8 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/crop_box_filter/crop_box_filter_node.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/crop_box_filter/crop_box_filter_node.cpp @@ -194,9 +194,9 @@ void CropBoxFilterComponent::faster_filter( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); auto pipeline_latency_ms = @@ -204,7 +204,7 @@ void CropBoxFilterComponent::faster_filter( std::chrono::nanoseconds((this->get_clock()->now() - input->header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug/pipeline_latency_ms", pipeline_latency_ms); } } diff --git a/sensing/autoware_pointcloud_preprocessor/src/distortion_corrector/distortion_corrector_node.cpp b/sensing/autoware_pointcloud_preprocessor/src/distortion_corrector/distortion_corrector_node.cpp index 9eaafeae9dbc7..cc05a6cc2765c 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/distortion_corrector/distortion_corrector_node.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/distortion_corrector/distortion_corrector_node.cpp @@ -123,7 +123,7 @@ void DistortionCorrectorComponent::pointcloud_callback(PointCloud2::UniquePtr po std::chrono::nanoseconds( (this->get_clock()->now() - pointcloud_msg->header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug/pipeline_latency_ms", pipeline_latency_ms); } @@ -133,9 +133,9 @@ void DistortionCorrectorComponent::pointcloud_callback(PointCloud2::UniquePtr po if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } diff --git a/sensing/autoware_pointcloud_preprocessor/src/downsample_filter/pickup_based_voxel_grid_downsample_filter_node.cpp b/sensing/autoware_pointcloud_preprocessor/src/downsample_filter/pickup_based_voxel_grid_downsample_filter_node.cpp index 3d2bc0a206c94..0c467234d6591 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/downsample_filter/pickup_based_voxel_grid_downsample_filter_node.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/downsample_filter/pickup_based_voxel_grid_downsample_filter_node.cpp @@ -142,9 +142,9 @@ void PickupBasedVoxelGridDownsampleFilterComponent::filter( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); auto pipeline_latency_ms = @@ -152,7 +152,7 @@ void PickupBasedVoxelGridDownsampleFilterComponent::filter( std::chrono::nanoseconds((this->get_clock()->now() - input->header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug/pipeline_latency_ms", pipeline_latency_ms); } } diff --git a/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/dual_return_outlier_filter_node.cpp b/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/dual_return_outlier_filter_node.cpp index a8024e02de2c1..bac3a59e09528 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/dual_return_outlier_filter_node.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/dual_return_outlier_filter_node.cpp @@ -65,7 +65,7 @@ DualReturnOutlierFilterComponent::DualReturnOutlierFilterComponent( image_pub_ = image_transport::create_publisher(this, "dual_return_outlier_filter/debug/frequency_image"); - visibility_pub_ = create_publisher( + visibility_pub_ = create_publisher( "dual_return_outlier_filter/debug/visibility", rclcpp::SensorDataQoS()); { rclcpp::PublisherOptions pub_options; @@ -322,7 +322,7 @@ void DualReturnOutlierFilterComponent::filter( frequency_image_msg->header = input->header; // Publish histogram image image_pub_.publish(frequency_image_msg); - tier4_debug_msgs::msg::Float32Stamped visibility_msg; + autoware_internal_debug_msgs::msg::Float32Stamped visibility_msg; visibility_msg.data = (1.0f - filled); visibility_msg.stamp = now(); visibility_pub_->publish(visibility_msg); diff --git a/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_node.cpp b/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_node.cpp index fae9043143ba4..fcea299ba5aff 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_node.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_node.cpp @@ -41,7 +41,7 @@ RingOutlierFilterComponent::RingOutlierFilterComponent(const rclcpp::NodeOptions outlier_pointcloud_publisher_ = this->create_publisher("debug/ring_outlier_filter", 1, pub_options); } - visibility_pub_ = create_publisher( + visibility_pub_ = create_publisher( "ring_outlier_filter/debug/visibility", rclcpp::SensorDataQoS()); stop_watch_ptr_->tic("cyclic_time"); stop_watch_ptr_->tic("processing_time"); @@ -262,7 +262,7 @@ void RingOutlierFilterComponent::faster_filter( outlier.header = input->header; outlier_pointcloud_publisher_->publish(outlier); - tier4_debug_msgs::msg::Float32Stamped visibility_msg; + autoware_internal_debug_msgs::msg::Float32Stamped visibility_msg; visibility_msg.data = calculateVisibilityScore(outlier); visibility_msg.stamp = input->header.stamp; visibility_pub_->publish(visibility_msg); @@ -272,9 +272,9 @@ void RingOutlierFilterComponent::faster_filter( if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); auto pipeline_latency_ms = @@ -282,7 +282,7 @@ void RingOutlierFilterComponent::faster_filter( std::chrono::nanoseconds((this->get_clock()->now() - input->header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug/pipeline_latency_ms", pipeline_latency_ms); } } diff --git a/sensing/autoware_pointcloud_preprocessor/src/time_synchronizer/time_synchronizer_node.cpp b/sensing/autoware_pointcloud_preprocessor/src/time_synchronizer/time_synchronizer_node.cpp index 42170fd88ee36..e5bd4a955590f 100644 --- a/sensing/autoware_pointcloud_preprocessor/src/time_synchronizer/time_synchronizer_node.cpp +++ b/sensing/autoware_pointcloud_preprocessor/src/time_synchronizer/time_synchronizer_node.cpp @@ -378,7 +378,7 @@ void PointCloudDataSynchronizerComponent::publish() std::chrono::nanoseconds( (this->get_clock()->now() - e.second->header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug" + e.first + "/pipeline_latency_ms", pipeline_latency_ms); } auto output = std::make_unique(*e.second); @@ -400,9 +400,9 @@ void PointCloudDataSynchronizerComponent::publish() if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); const double processing_time_ms = stop_watch_ptr_->toc("processing_time", true); - debug_publisher_->publish( + debug_publisher_->publish( "debug/cyclic_time_ms", cyclic_time_ms); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", processing_time_ms); } } From b20d7f05df2da1dd1580e824c82316ed77f49059 Mon Sep 17 00:00:00 2001 From: Mamoru Sobue Date: Wed, 15 Jan 2025 16:20:10 +0900 Subject: [PATCH 33/61] chore(autoware_test_utils): move rviz config to autoware_launch (#9925) Signed-off-by: Mamoru Sobue --- common/autoware_test_utils/CMakeLists.txt | 1 - .../launch/psim_intersection.launch.xml | 2 +- .../launch/psim_road_shoulder.launch.xml | 2 +- .../rviz/psim_test_map.rviz | 4569 ----------------- 4 files changed, 2 insertions(+), 4572 deletions(-) delete mode 100644 common/autoware_test_utils/rviz/psim_test_map.rviz diff --git a/common/autoware_test_utils/CMakeLists.txt b/common/autoware_test_utils/CMakeLists.txt index 8bfa44f7bf0ba..20b8f964f879f 100644 --- a/common/autoware_test_utils/CMakeLists.txt +++ b/common/autoware_test_utils/CMakeLists.txt @@ -25,5 +25,4 @@ ament_auto_package(INSTALL_TO_SHARE test_map test_data launch - rviz ) diff --git a/common/autoware_test_utils/launch/psim_intersection.launch.xml b/common/autoware_test_utils/launch/psim_intersection.launch.xml index 723dd7352219d..dc3e75cca1d96 100644 --- a/common/autoware_test_utils/launch/psim_intersection.launch.xml +++ b/common/autoware_test_utils/launch/psim_intersection.launch.xml @@ -3,7 +3,7 @@ - + diff --git a/common/autoware_test_utils/launch/psim_road_shoulder.launch.xml b/common/autoware_test_utils/launch/psim_road_shoulder.launch.xml index 7dd888a036f9d..58b71524e72b8 100644 --- a/common/autoware_test_utils/launch/psim_road_shoulder.launch.xml +++ b/common/autoware_test_utils/launch/psim_road_shoulder.launch.xml @@ -3,7 +3,7 @@ - + diff --git a/common/autoware_test_utils/rviz/psim_test_map.rviz b/common/autoware_test_utils/rviz/psim_test_map.rviz deleted file mode 100644 index 8475c94b86bb4..0000000000000 --- a/common/autoware_test_utils/rviz/psim_test_map.rviz +++ /dev/null @@ -1,4569 +0,0 @@ -Panels: - - Class: rviz_common/Displays - Help Height: 0 - Name: Displays - Property Tree Widget: - Expanded: - - /Sensing1/LiDAR1/ConcatenatePointCloud1/Autocompute Value Bounds1 - Splitter Ratio: 0.557669460773468 - Tree Height: 225 - - Class: rviz_common/Selection - Name: Selection - - Class: rviz_common/Tool Properties - Expanded: ~ - Name: Tool Properties - Splitter Ratio: 0.5886790156364441 - - Class: rviz_common/Views - Expanded: - - /Current View1 - Name: Views - Splitter Ratio: 0.5 - - Class: AutowareDateTimePanel - Name: AutowareDateTimePanel - - Class: rviz_plugins::AutowareStatePanel - Name: AutowareStatePanel - - Class: rviz_plugins::SimulatedClockPanel - Name: SimulatedClockPanel - - Class: rviz_plugins::TrafficLightPublishPanel - Name: TrafficLightPublishPanel -Visualization Manager: - Class: "" - Displays: - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/TF - Enabled: false - Frame Timeout: 15 - Frames: - All Enabled: true - Marker Scale: 1 - Name: TF - Show Arrows: true - Show Axes: true - Show Names: true - Tree: - {} - Update Interval: 0 - Value: false - - Alpha: 0.5 - Cell Size: 1 - Class: rviz_default_plugins/Grid - Color: 160; 160; 164 - Enabled: false - Line Style: - Line Width: 0.029999999329447746 - Value: Lines - Name: Grid - Normal Cell Count: 0 - Offset: - X: 0 - Y: 0 - Z: 0 - Plane: XY - Plane Cell Count: 10 - Reference Frame: - Value: false - - Class: rviz_common/Group - Displays: - - Alpha: 0.30000001192092896 - Class: rviz_default_plugins/RobotModel - Collision Enabled: false - Description File: "" - Description Source: Topic - Description Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /robot_description - Enabled: true - Links: - All Links Enabled: true - Expand Joint Details: false - Expand Link Details: false - Expand Tree: false - Link Tree Style: Links in Alphabetic Order - ars408_front_center: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera0/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera0/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - camera1/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera1/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - camera2/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera2/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - camera3/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera3/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - camera4/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera4/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - camera5/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera5/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - camera6/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera6/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - camera7/camera_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - camera7/camera_optical_link: - Alpha: 1 - Show Axes: false - Show Trail: false - gnss_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - livox_front_left: - Alpha: 1 - Show Axes: false - Show Trail: false - livox_front_left_base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - livox_front_right: - Alpha: 1 - Show Axes: false - Show Trail: false - livox_front_right_base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - sensor_kit_base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - tamagawa/imu_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_left: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_left_base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_rear: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_rear_base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_right: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_right_base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_top: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - velodyne_top_base_link: - Alpha: 1 - Show Axes: false - Show Trail: false - Value: true - Mass Properties: - Inertia: false - Mass: false - Name: VehicleModel - TF Prefix: "" - Update Interval: 0 - Value: true - Visual Enabled: true - - Class: rviz_plugins/PolarGridDisplay - Color: 255; 255; 255 - Delta Range: 10 - Enabled: true - Max Alpha: 0.5 - Max Range: 100 - Max Wave Alpha: 0.5 - Min Alpha: 0.009999999776482582 - Min Wave Alpha: 0.009999999776482582 - Name: PolarGridDisplay - Reference Frame: base_link - Value: true - Wave Color: 255; 255; 255 - Wave Velocity: 40 - - Background Alpha: 0.5 - Background Color: 23; 28; 31 - Class: autoware_overlay_rviz_plugin/SignalDisplay - Dark Traffic Color: 255; 51; 51 - Enabled: true - Gear Topic Test: /vehicle/status/gear_status - Handle Angle Scale: 17 - Hazard Lights Topic: /vehicle/status/hazard_lights_status - Height: 100 - Left: 0 - Light Traffic Color: 255; 153; 153 - Name: SignalDisplay - Primary Color: 174; 174; 174 - Signal Color: 0; 230; 120 - Speed Limit Topic: /planning/scenario_planning/current_max_velocity - Speed Topic: /vehicle/status/velocity_status - Steering Topic: /vehicle/status/steering_status - Top: 10 - Traffic Topic: /planning/scenario_planning/lane_driving/behavior_planning/debug/traffic_signal - Turn Signals Topic: /vehicle/status/turn_indicators_status - Value: true - Width: 550 - Enabled: true - Name: Vehicle - - Class: rviz_plugins/MrmSummaryOverlayDisplay - Enabled: false - Font Size: 10 - Left: 512 - Max Letter Num: 100 - Name: MRM Summary - Text Color: 25; 255; 240 - Top: 64 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /system/emergency/hazard_status - Value: false - Value height offset: 0 - Enabled: true - Name: System - - Class: rviz_common/Group - Displays: - - Alpha: 0.20000000298023224 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 28.71826171875 - Min Value: -7.4224700927734375 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: FlatColor - Decay Time: 0 - Enabled: false - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 237 - Min Color: 211; 215; 207 - Min Intensity: 0 - Name: PointCloudMap - Position Transformer: XYZ - Selectable: false - Size (Pixels): 1 - Size (m): 0.019999999552965164 - Style: Points - Topic: - Depth: 5 - Durability Policy: Transient Local - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /map/pointcloud_map - Use Fixed Frame: true - Use rainbow: false - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: Lanelet2VectorMap - Namespaces: - bus_stop_area: true - center_lane_line: false - center_line_arrows: false - curbstone: true - lane_start_bound: false - lanelet direction: true - lanelet_id: false - left_lane_bound: true - no_parking_area: true - parking_lots: true - parking_space: true - partitions: true - right_lane_bound: true - road_lanelets: false - shoulder_center_lane_line: false - shoulder_center_line_arrows: true - shoulder_lane_start_bound: true - shoulder_left_lane_bound: true - shoulder_right_lane_bound: true - shoulder_road_lanelets: false - Topic: - Depth: 5 - Durability Policy: Transient Local - History Policy: Keep Last - Reliability Policy: Reliable - Value: /map/vector_map_marker - Value: true - Enabled: true - Name: Map - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - Alpha: 0.4000000059604645 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 5 - Min Value: -1 - Value: false - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: AxisColor - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 4096 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: ConcatenatePointCloud - Position Transformer: XYZ - Selectable: false - Size (Pixels): 1 - Size (m): 0.019999999552965164 - Style: Points - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /sensing/lidar/concatenated/pointcloud - Use Fixed Frame: false - Use rainbow: true - Value: true - - Alpha: 0.9990000128746033 - Class: rviz_default_plugins/Polygon - Color: 25; 255; 0 - Enabled: false - Name: MeasurementRange - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /sensing/lidar/crop_box_filter/crop_box_polygon - Value: false - Enabled: true - Name: LiDAR - - Class: rviz_common/Group - Displays: - - Alpha: 0.9990000128746033 - Axes Length: 1 - Axes Radius: 0.10000000149011612 - Class: rviz_default_plugins/PoseWithCovariance - Color: 233; 185; 110 - Covariance: - Orientation: - Alpha: 0.5 - Color: 255; 255; 127 - Color Style: Unique - Frame: Local - Offset: 1 - Scale: 1 - Value: false - Position: - Alpha: 0.20000000298023224 - Color: 204; 51; 204 - Scale: 1 - Value: true - Value: true - Enabled: true - Head Length: 0.699999988079071 - Head Radius: 1.2000000476837158 - Name: PoseWithCovariance - Shaft Length: 1 - Shaft Radius: 0.5 - Shape: Arrow - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /sensing/gnss/pose_with_covariance - Value: true - Enabled: false - Name: GNSS - Enabled: true - Name: Sensing - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - Alpha: 0.9990000128746033 - Axes Length: 1 - Axes Radius: 0.10000000149011612 - Class: rviz_default_plugins/PoseWithCovariance - Color: 0; 170; 255 - Covariance: - Orientation: - Alpha: 0.5 - Color: 255; 255; 127 - Color Style: Unique - Frame: Local - Offset: 1 - Scale: 1 - Value: true - Position: - Alpha: 0.30000001192092896 - Color: 204; 51; 204 - Scale: 1 - Value: true - Value: true - Enabled: false - Head Length: 0.4000000059604645 - Head Radius: 0.6000000238418579 - Name: PoseWithCovInitial - Shaft Length: 0.6000000238418579 - Shaft Radius: 0.30000001192092896 - Shape: Arrow - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/initial_pose_with_covariance - Value: false - - Alpha: 0.9990000128746033 - Axes Length: 1 - Axes Radius: 0.10000000149011612 - Class: rviz_default_plugins/PoseWithCovariance - Color: 0; 255; 0 - Covariance: - Orientation: - Alpha: 0.5 - Color: 255; 255; 127 - Color Style: Unique - Frame: Local - Offset: 1 - Scale: 1 - Value: true - Position: - Alpha: 0.30000001192092896 - Color: 204; 51; 204 - Scale: 1 - Value: true - Value: true - Enabled: false - Head Length: 0.4000000059604645 - Head Radius: 0.6000000238418579 - Name: PoseWithCovAligned - Shaft Length: 0.6000000238418579 - Shaft Radius: 0.30000001192092896 - Shape: Arrow - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/pose_with_covariance - Value: false - - Buffer Size: 200 - Class: rviz_plugins::PoseHistory - Enabled: false - Line: - Alpha: 0.9990000128746033 - Color: 170; 255; 127 - Value: true - Width: 0.10000000149011612 - Name: PoseHistory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/pose - Value: false - - Alpha: 0.9990000128746033 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 0; 255; 255 - Color Transformer: "" - Decay Time: 0 - Enabled: false - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 4096 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: Initial - Position Transformer: XYZ - Selectable: false - Size (Pixels): 10 - Size (m): 0.5 - Style: Squares - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /localization/util/downsample/pointcloud - Use Fixed Frame: true - Use rainbow: true - Value: false - - Alpha: 0.9990000128746033 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 85; 255; 0 - Color Transformer: FlatColor - Decay Time: 0 - Enabled: false - Invert Rainbow: false - Max Color: 85; 255; 127 - Max Intensity: 0 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: Aligned - Position Transformer: XYZ - Selectable: false - Size (Pixels): 10 - Size (m): 0.5 - Style: Squares - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/points_aligned - Use Fixed Frame: true - Use rainbow: true - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: MonteCarloInitialPose - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/monte_carlo_initial_pose_marker - Value: true - Enabled: true - Name: NDT - - Class: rviz_common/Group - Displays: - - Buffer Size: 1000 - Class: rviz_plugins::PoseHistory - Enabled: true - Line: - Alpha: 0.9990000128746033 - Color: 0; 255; 255 - Value: true - Width: 0.10000000149011612 - Name: PoseHistory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_twist_fusion_filter/pose - Value: true - Enabled: true - Name: EKF - Enabled: true - Name: Localization - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - Alpha: 0.9990000128746033 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 15 - Min Value: -2 - Value: false - Axis: Z - Channel Name: z - Class: rviz_default_plugins/PointCloud2 - Color: 200; 200; 200 - Color Transformer: FlatColor - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 15 - Min Color: 0; 0; 0 - Min Intensity: -5 - Name: NoGroundPointCloud - Position Transformer: XYZ - Selectable: false - Size (Pixels): 3 - Size (m): 0.019999999552965164 - Style: Points - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/obstacle_segmentation/pointcloud - Use Fixed Frame: true - Use rainbow: true - Value: true - Enabled: true - Name: Segmentation - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - BUS: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - CAR: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 119; 11; 32 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.029999999329447746 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 119; 11; 32 - Name: DetectedObjects - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 192; 203 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - TRUCK: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Value: true - Visualization Type: Normal - Enabled: false - Name: Detection - - Class: rviz_common/Group - Displays: - - BUS: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - CAR: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 119; 11; 32 - Class: autoware_perception_rviz_plugin/TrackedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Dynamic Status: All - Enabled: true - Line Width: 0.029999999329447746 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 119; 11; 32 - Name: TrackedObjects - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 192; 203 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - TRUCK: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/tracking/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Value: true - Visualization Type: Normal - Enabled: false - Name: Tracking - - Class: rviz_common/Group - Displays: - - BUS: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - CAR: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 119; 11; 32 - Class: autoware_perception_rviz_plugin/PredictedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.029999999329447746 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 119; 11; 32 - Name: PredictedObjects - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 192; 203 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - TRUCK: - Alpha: 0.9990000128746033 - Color: 30; 144; 255 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Value: true - Visualization Type: Normal - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Maneuver - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/prediction/maneuver - Value: false - Enabled: true - Name: Prediction - Enabled: true - Name: ObjectRecognition - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/Image - Enabled: false - Max Value: 1 - Median window: 5 - Min Value: 0 - Name: RecognitionResultOnImage - Normalize Range: true - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/traffic_light_recognition/traffic_light/debug/rois - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: MapBasedDetectionResult - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/traffic_light_recognition/traffic_light_map_based_detector/debug/markers - Value: true - Enabled: true - Name: TrafficLight - - Class: rviz_common/Group - Displays: - - Alpha: 0.5 - Class: rviz_default_plugins/Map - Color Scheme: map - Draw Behind: false - Enabled: true - Name: Map - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/occupancy_grid_map/map - Update Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/occupancy_grid_map/map_updates - Use Timestamp: false - Value: true - Enabled: false - Name: OccupancyGrid - Enabled: true - Name: Perception - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: RouteArea - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Transient Local - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/mission_planning/route_marker - Value: true - - Alpha: 0.9990000128746033 - Axes Length: 1 - Axes Radius: 0.30000001192092896 - Class: rviz_default_plugins/Pose - Color: 255; 25; 0 - Enabled: true - Head Length: 0.30000001192092896 - Head Radius: 0.5 - Name: GoalPose - Shaft Length: 3 - Shaft Radius: 0.20000000298023224 - Shape: Axes - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/mission_planning/echo_back_goal_pose - Value: true - - Background Alpha: 0.5 - Background Color: 23; 28; 31 - Class: autoware_mission_details_overlay_rviz_plugin/MissionDetailsDisplay - Enabled: true - Height: 100 - Name: MissionDetailsDisplay - Remaining Distance and Time Topic: /planning/mission_remaining_distance_time - Right: 10 - Text Color: 194; 194; 194 - Top: 10 - Value: true - Width: 170 - Enabled: true - Name: MissionPlanning - - Class: rviz_common/Group - Displays: - - Class: rviz_plugins/Trajectory - Color Border Vel Max: 3 - Enabled: true - Name: ScenarioTrajectory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/trajectory - Value: true - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.9990000128746033 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.9990000128746033 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: true - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: Path - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/path - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.4000000059604645 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.4000000059604645 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: true - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: false - Name: PathReference_AvoidanceByLC - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_reference/avoidance_by_lane_change - Value: false - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: false - Name: PathReference_Avoidance - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_reference/static_obstacle_avoidance - Value: false - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: false - Name: PathReference_LaneChangeRight - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_reference/lane_change_right - Value: false - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: false - Name: PathReference_LaneChangeLeft - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_reference/lane_change_left - Value: false - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: false - Name: PathReference_GoalPlanner - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_reference/goal_planner - Value: false - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: false - Name: PathReference_StartPlanner - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_reference/start_planner - Value: false - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_AvoidanceByLC - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/avoidance_by_lane_change - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: (old)PathChangeCandidate_LaneChange - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/lane_change - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_LaneChangeRight - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/lane_change_right - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_LaneChangeLeft - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/lane_change_left - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_ExternalRequestLaneChangeRight - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/external_request_lane_change_right - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_ExternalRequestLaneChangeLeft - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/external_request_lane_change_left - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_Avoidance - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/static_obstacle_avoidance - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_StartPlanner - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/start_planner - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Path - Color Border Vel Max: 3 - Enabled: true - Name: PathChangeCandidate_GoalPlanner - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/path_candidate/goal_planner - Value: true - View Drivable Area: - Alpha: 0.9990000128746033 - Color: 0; 148; 205 - Value: true - Width: 0.30000001192092896 - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.30000001192092896 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.30000001192092896 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Bound - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/bound - Value: false - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (StaticObstacleAvoidance) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/static_obstacle_avoidance - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (AvoidanceByLC) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/avoidance_by_lane_change - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (LaneChangeRight) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/lane_change_right - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (LaneChangeLeft) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/lane_change_left - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (ExtLaneChangeRight) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/external_request_lane_change_right - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (ExtLaneChangeLeft) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/external_request_lane_change_left - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (GoalPlanner) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/goal_planner - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (StartPlanner) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/virtual_wall/start_planner - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (BlindSpot) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/blind_spot - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (Crosswalk) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/crosswalk - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (Walkway) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/walkway - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (DetectionArea) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/detection_area - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (Intersection) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/intersection - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (MergeFromPrivateArea) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/merge_from_private - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (NoStoppingArea) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/no_stopping_area - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (OcclusionSpot) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/occlusion_spot - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (StopLine) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/stop_line - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (TrafficLight) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/traffic_light - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (VirtualTrafficLight) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/virtual_traffic_light - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (RunOut) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/run_out - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (SpeedBump) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/speed_bump - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (NoDrivableLane) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/virtual_wall/no_drivable_lane - Value: true - Enabled: true - Name: VirtualWall - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Arrow - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/path - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Crosswalk - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/crosswalk - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Intersection - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/intersection - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Blind Spot - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/blind_spot - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: TrafficLight - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/traffic_light - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: VirtualTrafficLight - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/virtual_traffic_light - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: StopLine - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/stop_line - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: DetectionArea - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/detection_area - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: OcclusionSpot - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/occlusion_spot - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: NoStoppingArea - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/no_stopping_area - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: RunOut - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/run_out - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: StaticObstacleAvoidance - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/static_obstacle_avoidance - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: LeftLaneChange - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/lane_change_left - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: RightLaneChange - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/lane_change_right - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: LaneFollowing - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/lane_following - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: GoalPlanner - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/goal_planner - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: StartPlanner - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/start_planner - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: SideShift - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/side_shift - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: SpeedBump - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/speed_bump - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: DynamicObstacleAvoidance - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/debug/dynamic_obstacle_avoidance - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: NoDrivableLane - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_velocity_planner/debug/no_drivable_lane - Value: false - Enabled: false - Name: DebugMarker - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (StaticObstacleAvoidance) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/static_obstacle_avoidance - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (AvoidanceByLC) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/avoidance_by_lane_change - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (LaneChangeLeft) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/lane_change_left - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (LaneChangeRight) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/lane_change_right - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (ExtLaneChangeLeft) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/external_request_lane_change_left - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (ExtLaneChangeRight) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/external_request_lane_change_right - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (GoalPlanner) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/goal_planner - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (StartPlanner) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/start_planner - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Info (DynamicObstacleAvoidance) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/behavior_planning/behavior_path_planner/info/dynamic_obstacle_avoidance - Value: false - Enabled: false - Name: InfoMarker - Enabled: true - Name: BehaviorPlanning - - Class: rviz_common/Group - Displays: - - Class: rviz_plugins/Trajectory - Color Border Vel Max: 3 - Enabled: false - Name: Trajectory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/trajectory - Value: false - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 0.9990000128746033 - Constant Width: false - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 2 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 0.9990000128746033 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: true - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (ObstacleStop) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_stop_planner/virtual_wall - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (SurroundObstacle) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/surround_obstacle_checker/virtual_wall - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (ObstacleAvoidance) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_avoidance_planner/virtual_wall - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (ObstacleCruise) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_cruise_planner/virtual_wall - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (MotionVelocitySmoother) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/velocity_smoother/virtual_wall - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (OutOfLane) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/motion_velocity_planner/out_of_lane/virtual_walls - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (ObstacleVelocityLimiter) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/motion_velocity_planner/obstacle_velocity_limiter/virtual_walls - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (DynamicObstacleStop) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/motion_velocity_planner/dynamic_obstacle_stop/virtual_walls - Value: true - Enabled: true - Name: VirtualWall - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: SurroundObstacleCheck - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/surround_obstacle_checker/debug/marker - Value: true - - Alpha: 1 - Class: rviz_default_plugins/Polygon - Color: 25; 255; 0 - Enabled: false - Name: Footprint - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/surround_obstacle_checker/debug/footprint - Value: false - - Alpha: 1 - Class: rviz_default_plugins/Polygon - Color: 239; 41; 41 - Enabled: false - Name: FootprintOffset - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/surround_obstacle_checker/debug/footprint_offset - Value: false - - Alpha: 1 - Class: rviz_default_plugins/Polygon - Color: 10; 21; 255 - Enabled: false - Name: FootprintRecoverOffset - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/surround_obstacle_checker/debug/footprint_recover_offset - Value: false - Enabled: false - Name: SurroundObstacleChecker - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: ObstacleStop - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_stop_planner/debug/marker - Value: false - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: CruiseVirtualWall - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_cruise_planner/debug/cruise/virtual_wall - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: SlowDownVirtualWall - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_cruise_planner/debug/slow_down/virtual_wall - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: DebugMarker - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_cruise_planner/debug/marker - Value: true - Enabled: false - Name: ObstacleCruise - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: ObstacleAvoidance - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/obstacle_avoidance_planner/debug/marker - Value: false - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: OutOfLane - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/motion_velocity_planner/out_of_lane/debug_markers - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: ObstacleVelocityLimiter - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/motion_velocity_planner/obstacle_velocity_limiter/debug_markers - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: DynamicObstacleStop - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/lane_driving/motion_planning/motion_velocity_planner/dynamic_obstacle_stop/debug_markers - Value: true - Enabled: false - Name: MotionVelocityPlanner - Enabled: false - Name: DebugMarker - Enabled: true - Name: MotionPlanning - Enabled: true - Name: LaneDriving - - Class: rviz_common/Group - Displays: - - Alpha: 0.699999988079071 - Class: rviz_default_plugins/Map - Color Scheme: map - Draw Behind: false - Enabled: false - Name: Costmap - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/parking/costmap_generator/occupancy_grid - Update Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/parking/costmap_generator/occupancy_grid_updates - Use Timestamp: false - Value: false - - Alpha: 0.9990000128746033 - Arrow Length: 0.30000001192092896 - Axes Length: 0.30000001192092896 - Axes Radius: 0.009999999776482582 - Class: rviz_default_plugins/PoseArray - Color: 255; 25; 0 - Enabled: true - Head Length: 0.10000000149011612 - Head Radius: 0.20000000298023224 - Name: PartialPoseArray - Shaft Length: 0.20000000298023224 - Shaft Radius: 0.05000000074505806 - Shape: Arrow (3D) - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/parking/freespace_planner/debug/partial_pose_array - Value: true - - Alpha: 0.9990000128746033 - Arrow Length: 0.5 - Axes Length: 0.30000001192092896 - Axes Radius: 0.009999999776482582 - Class: rviz_default_plugins/PoseArray - Color: 0; 0; 255 - Enabled: true - Head Length: 0.10000000149011612 - Head Radius: 0.20000000298023224 - Name: PoseArray - Shaft Length: 0.20000000298023224 - Shaft Radius: 0.05000000074505806 - Shape: Arrow (Flat) - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/parking/freespace_planner/debug/pose_array - Value: true - Enabled: true - Name: Parking - - Class: rviz_plugins/PoseWithUuidStamped - Enabled: true - Length: 1.5 - Name: ModifiedGoal - Radius: 0.5 - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/scenario_planning/modified_goal - UUID: - Scale: 0.30000001192092896 - Value: false - Value: true - Enabled: true - Name: ScenarioPlanning - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: PlanningErrorMarker - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /planning/planning_diagnostics/planning_error_monitor/debug/marker - Value: true - Enabled: false - Name: Diagnostic - Enabled: true - Name: Planning - - Class: rviz_common/Group - Displays: - - Class: rviz_plugins/Trajectory - Color Border Vel Max: 3 - Enabled: true - Name: Predicted Trajectory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /control/trajectory_follower/controller_node_exe/debug/predicted_trajectory_in_frenet_coordinate - Value: true - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 1 - Constant Width: true - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: true - Width: 0.05000000074505806 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: false - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 1 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_plugins/Trajectory - Color Border Vel Max: 3 - Enabled: false - Name: Resampled Reference Trajectory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /control/trajectory_follower/controller_node_exe/debug/resampled_reference_trajectory - Value: false - View Footprint: - Alpha: 1 - Color: 230; 230; 50 - Offset from BaseLink: 0 - Rear Overhang: 1.0299999713897705 - Value: false - Vehicle Length: 4.769999980926514 - Vehicle Width: 1.8300000429153442 - View Path: - Alpha: 1 - Constant Width: true - Fade Out Distance: 0 - Max Velocity Color: 0; 230; 120 - Mid Velocity Color: 32; 138; 174 - Min Velocity Color: 63; 46; 227 - Value: false - Width: 0.20000000298023224 - View Point: - Alpha: 1 - Color: 0; 60; 255 - Offset: 0 - Radius: 0.10000000149011612 - Value: true - View Text Slope: - Scale: 0.30000001192092896 - Value: false - View Text Velocity: - Scale: 0.30000001192092896 - Value: false - View Velocity: - Alpha: 1 - Color: 0; 0; 0 - Constant Color: false - Scale: 0.30000001192092896 - Value: false - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: VirtualWall (AEB) - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /control/autonomous_emergency_braking/virtual_wall - Value: true - Enabled: true - Name: VirtualWall - - Class: rviz_default_plugins/Marker - Enabled: false - Name: Stop Reason - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /control/trajectory_follower/longitudinal/stop_reason - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Debug/MPC - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /control/trajectory_follower/mpc_follower/debug/markers - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Debug/PurePursuit - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /control/trajectory_follower/controller_node_exe/debug/markers - Value: false - - Class: rviz_default_plugins/MarkerArray - Enabled: false - Name: Debug/AEB - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /control/autonomous_emergency_braking/debug/markers - Value: false - Enabled: true - Name: Control - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: ~ - Enabled: true - Name: Map - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/Camera - Enabled: true - Far Plane Distance: 100 - Image Rendering: background and overlay - Name: PointcloudOnCamera - Overlay Alpha: 0.5 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /sensing/camera/camera6/image_raw - Value: true - Visibility: - Control: - Debug/AEB: true - Debug/MPC: true - Debug/PurePursuit: true - Predicted Trajectory: true - Resampled Reference Trajectory: true - Stop Reason: true - Value: false - VirtualWall: - Value: true - VirtualWall (AEB): true - Debug: - Control: true - Localization: - "": true - Value: true - Map: true - Perception: - "": true - Value: true - Planning: - "": - "": true - Value: true - Value: true - Sensing: - ConcatenatePointCloud: true - RadarRawObjects(white): true - Value: true - Value: true - Localization: - EKF: - PoseHistory: true - Value: true - NDT: - Aligned: true - Initial: true - MonteCarloInitialPose: true - PoseHistory: true - PoseWithCovAligned: true - PoseWithCovInitial: true - Value: true - Value: false - Map: - Lanelet2VectorMap: true - PointCloudMap: true - Value: false - Perception: - ObjectRecognition: - Detection: - DetectedObjects: true - Value: true - Prediction: - Maneuver: true - PredictedObjects: true - Value: true - Tracking: - TrackedObjects: true - Value: true - Value: true - OccupancyGrid: - Map: true - Value: true - Segmentation: - NoGroundPointCloud: true - Value: true - TrafficLight: - MapBasedDetectionResult: true - RecognitionResultOnImage: true - Value: true - Value: false - Planning: - Diagnostic: - PlanningErrorMarker: true - Value: true - MissionPlanning: - GoalPose: true - MissionDetailsDisplay: true - RouteArea: true - Value: true - ScenarioPlanning: - LaneDriving: - BehaviorPlanning: - (old)PathChangeCandidate_LaneChange: true - Bound: true - DebugMarker: - Arrow: true - Blind Spot: true - Crosswalk: true - DetectionArea: true - DynamicObstacleAvoidance: true - GoalPlanner: true - Intersection: true - LaneFollowing: true - LeftLaneChange: true - NoDrivableLane: true - NoStoppingArea: true - OcclusionSpot: true - RightLaneChange: true - RunOut: true - SideShift: true - SpeedBump: true - StartPlanner: true - StaticObstacleAvoidance: true - StopLine: true - TrafficLight: true - Value: true - VirtualTrafficLight: true - InfoMarker: - Info (AvoidanceByLC): true - Info (DynamicObstacleAvoidance): true - Info (ExtLaneChangeLeft): true - Info (ExtLaneChangeRight): true - Info (GoalPlanner): true - Info (LaneChangeLeft): true - Info (LaneChangeRight): true - Info (StartPlanner): true - Info (StaticObstacleAvoidance): true - Value: true - Path: true - PathChangeCandidate_Avoidance: true - PathChangeCandidate_AvoidanceByLC: true - PathChangeCandidate_ExternalRequestLaneChangeLeft: true - PathChangeCandidate_ExternalRequestLaneChangeRight: true - PathChangeCandidate_GoalPlanner: true - PathChangeCandidate_LaneChangeLeft: true - PathChangeCandidate_LaneChangeRight: true - PathChangeCandidate_StartPlanner: true - PathReference_Avoidance: true - PathReference_AvoidanceByLC: true - PathReference_GoalPlanner: true - PathReference_LaneChangeLeft: true - PathReference_LaneChangeRight: true - PathReference_StartPlanner: true - Value: true - VirtualWall: - Value: true - VirtualWall (AvoidanceByLC): true - VirtualWall (BlindSpot): true - VirtualWall (Crosswalk): true - VirtualWall (DetectionArea): true - VirtualWall (ExtLaneChangeLeft): true - VirtualWall (ExtLaneChangeRight): true - VirtualWall (GoalPlanner): true - VirtualWall (Intersection): true - VirtualWall (LaneChangeLeft): true - VirtualWall (LaneChangeRight): true - VirtualWall (MergeFromPrivateArea): true - VirtualWall (NoDrivableLane): true - VirtualWall (NoStoppingArea): true - VirtualWall (OcclusionSpot): true - VirtualWall (RunOut): true - VirtualWall (SpeedBump): true - VirtualWall (StartPlanner): true - VirtualWall (StaticObstacleAvoidance): true - VirtualWall (StopLine): true - VirtualWall (TrafficLight): true - VirtualWall (VirtualTrafficLight): true - VirtualWall (Walkway): true - MotionPlanning: - DebugMarker: - MotionVelocityPlanner: - DynamicObstacleStop: true - ObstacleVelocityLimiter: true - OutOfLane: true - Value: true - ObstacleAvoidance: true - ObstacleCruise: - CruiseVirtualWall: true - DebugMarker: true - SlowDownVirtualWall: true - Value: true - ObstacleStop: true - SurroundObstacleChecker: - Footprint: true - FootprintOffset: true - FootprintRecoverOffset: true - SurroundObstacleCheck: true - Value: true - Value: true - Trajectory: true - Value: true - VirtualWall: - Value: true - VirtualWall (DynamicObstacleStop): true - VirtualWall (MotionVelocitySmoother): true - VirtualWall (ObstacleAvoidance): true - VirtualWall (ObstacleCruise): true - VirtualWall (ObstacleStop): true - VirtualWall (ObstacleVelocityLimiter): true - VirtualWall (OutOfLane): true - VirtualWall (SurroundObstacle): true - Value: true - ModifiedGoal: true - Parking: - Costmap: true - PartialPoseArray: true - PoseArray: true - Value: true - ScenarioTrajectory: true - Value: true - Value: false - Sensing: - GNSS: - PoseWithCovariance: true - Value: true - LiDAR: - ConcatenatePointCloud: true - MeasurementRange: true - Value: true - Value: true - System: - Grid: true - MRM Summary: true - TF: true - Value: false - Vehicle: - PolarGridDisplay: true - SignalDisplay: true - Value: true - VehicleModel: true - Value: true - Zoom Factor: 1 - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 5 - Min Value: -1 - Value: false - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: AxisColor - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 4096 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: ConcatenatePointCloud - Position Transformer: XYZ - Selectable: false - Size (Pixels): 3 - Size (m): 0.019999999552965164 - Style: Points - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /sensing/lidar/concatenated/pointcloud - Use Fixed Frame: false - Use rainbow: true - Value: true - - BUS: - Alpha: 0.5 - Color: 255; 255; 255 - CAR: - Alpha: 0.5 - Color: 255; 255; 255 - CYCLIST: - Alpha: 0.5 - Color: 255; 255; 255 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.029999999329447746 - MOTORCYCLE: - Alpha: 0.5 - Color: 255; 255; 255 - Name: RadarRawObjects(white) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.5 - Color: 255; 255; 255 - Polygon Type: 3d - TRAILER: - Alpha: 0.5 - Color: 255; 255; 255 - TRUCK: - Alpha: 0.5 - Color: 255; 255; 255 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /sensing/radar/detected_objects - UNKNOWN: - Alpha: 0.5 - Color: 255; 255; 255 - Value: true - Visualization Type: Normal - Enabled: false - Name: Sensing - - Class: rviz_common/Group - Displays: - - Alpha: 0.9990000128746033 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 85; 255; 0 - Color Transformer: FlatColor - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 85; 255; 127 - Max Intensity: 0 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: NDT pointclouds - Position Transformer: XYZ - Selectable: false - Size (Pixels): 10 - Size (m): 0.5 - Style: Squares - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/points_aligned - Use Fixed Frame: true - Use rainbow: true - Value: true - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: "" - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 4096 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: NDTLoadedPCDMap - Position Transformer: "" - Selectable: true - Size (Pixels): 3 - Size (m): 0.10000000149011612 - Style: Flat Squares - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/debug/loaded_pointcloud_map - Use Fixed Frame: true - Use rainbow: true - Value: true - - Buffer Size: 200 - Class: rviz_plugins::PoseHistory - Enabled: true - Line: - Alpha: 0.9990000128746033 - Color: 170; 255; 127 - Value: true - Width: 0.10000000149011612 - Name: NDTPoseHistory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_estimator/pose - Value: true - - Buffer Size: 1000 - Class: rviz_plugins::PoseHistory - Enabled: true - Line: - Alpha: 0.9990000128746033 - Color: 0; 255; 255 - Value: true - Width: 0.10000000149011612 - Name: EKFPoseHistory - Topic: - Depth: 5 - Durability Policy: Volatile - Filter size: 10 - History Policy: Keep Last - Reliability Policy: Reliable - Value: /localization/pose_twist_fusion_filter/pose - Value: true - Enabled: true - Name: Localization - - Class: rviz_common/Group - Displays: - - BUS: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - CAR: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - Name: Centerpoint(red1) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - TRUCK: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/centerpoint/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 138; 128 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - CAR: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - Name: CenterpointROIFusion(red2) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - TRUCK: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/centerpoint/roi_fusion/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 82; 82 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - CAR: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - Name: CenterpointValidator(red3) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - TRUCK: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/centerpoint/validation/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 213; 0; 0 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - CAR: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - Name: PointPainting(light_green1) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - TRUCK: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/pointpainting/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 178; 255; 89 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - CAR: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - Name: PointPaintingROIFusion(light_green2) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - TRUCK: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/pointpainting/roi_fusion/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 118; 255; 3 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - CAR: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - Name: PointPaintingValidator(light_green3) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - TRUCK: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/pointpainting/validation/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 100; 221; 23 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - CAR: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - Name: DetectionByTracker(orange) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - TRUCK: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/detection_by_tracker/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 145; 0 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - CAR: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - Name: CameraLidarFusion(purple) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - TRUCK: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/clustering/camera_lidar_fusion/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 213; 0; 249 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - CAR: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Name: RadarFarObjects(white) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - TRUCK: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/radar/far_objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 255; 255 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - CAR: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - Class: autoware_perception_rviz_plugin/DetectedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - Name: Detection(yellow) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - TRUCK: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/detection/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 255; 234; 0 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - CAR: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - Class: autoware_perception_rviz_plugin/TrackedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Dynamic Status: All - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - Name: Tracking(green) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - TRUCK: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/tracking/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 0; 230; 118 - Value: true - Visualization Type: Normal - - BUS: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - CAR: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - CYCLIST: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - Class: autoware_perception_rviz_plugin/PredictedObjects - Confidence Interval: 95% - Display Acceleration: true - Display Existence Probability: false - Display Label: true - Display Pose Covariance: true - Display Predicted Path Confidence: true - Display Predicted Paths: true - Display Twist: true - Display Twist Covariance: false - Display UUID: true - Display Velocity: true - Display Yaw Covariance: false - Display Yaw Rate: false - Display Yaw Rate Covariance: false - Enabled: true - Line Width: 0.10000000149011612 - MOTORCYCLE: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - Name: Prediction(light_blue) - Namespaces: - {} - Object Fill Type: skeleton - PEDESTRIAN: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - Polygon Type: 3d - TRAILER: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - TRUCK: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Best Effort - Value: /perception/object_recognition/objects - UNKNOWN: - Alpha: 0.9990000128746033 - Color: 0; 176; 255 - Value: true - Visualization Type: Normal - Enabled: true - Name: Perception - - Class: rviz_common/Group - Displays: - - Class: rviz_common/Group - Displays: - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: LaneChangeLeft - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/lane_change_left - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: LaneChangeRight - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/lane_change_right - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: AvoidanceLeft - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/static_obstacle_avoidance_left - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: AvoidanceRight - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/static_obstacle_avoidance_right - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: AvoidanceByLCLeft - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/avoidance_by_lc_left - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: AvoidanceByLCRight - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/avoidance_by_lc_right - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: StartPlanner - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/start_planner - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: GoalPlanner - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/goal_planner - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: Crosswalk - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/crosswalk - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: Intersection - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/intersection - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: BlindSpot - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/blind_spot - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: TrafficLight - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/traffic_light - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: DetectionArea - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/detection_area - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: NoStoppingArea - Namespaces: - {} - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/debug/objects_of_interest/no_stopping_area - Value: true - Enabled: true - Name: Objects Of Interest - Enabled: true - Name: Planning - - Class: rviz_common/Group - Displays: ~ - Enabled: true - Name: Control - Enabled: false - Name: Debug - Enabled: true - Global Options: - Background Color: 15; 20; 23 - Fixed Frame: map - Frame Rate: 30 - Name: root - Tools: - - Class: rviz_default_plugins/Interact - Hide Inactive Objects: true - - Class: rviz_default_plugins/MoveCamera - - Class: rviz_default_plugins/Select - - Class: rviz_default_plugins/FocusCamera - - Class: rviz_default_plugins/Measure - Line color: 128; 128; 0 - - Class: rviz_default_plugins/SetInitialPose - Covariance x: 0.25 - Covariance y: 0.25 - Covariance yaw: 0.06853891909122467 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /initialpose - - Class: rviz_default_plugins/SetGoal - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /planning/mission_planning/goal - - Class: tier4_adapi_rviz_plugins::RouteTool - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /rviz/routing/rough_goal - - Acceleration: 0 - Class: rviz_plugins/PedestrianInitialPoseTool - Interactive: false - Max velocity: 33.29999923706055 - Min velocity: -33.29999923706055 - Pose Topic: /simulation/dummy_perception_publisher/object_info - Target Frame: - Theta std deviation: 0.0872664600610733 - Velocity: 0 - X std deviation: 0.029999999329447746 - Y std deviation: 0.029999999329447746 - Z position: 1 - Z std deviation: 0.029999999329447746 - - Acceleration: 0 - Class: rviz_plugins/CarInitialPoseTool - H vehicle height: 2 - Interactive: false - L vehicle length: 4 - Max velocity: 33.29999923706055 - Min velocity: -33.29999923706055 - Pose Topic: /simulation/dummy_perception_publisher/object_info - Target Frame: - Theta std deviation: 0.0872664600610733 - Velocity: 3 - W vehicle width: 1.7999999523162842 - X std deviation: 0.029999999329447746 - Y std deviation: 0.029999999329447746 - Z position: 0 - Z std deviation: 0.029999999329447746 - - Acceleration: 0 - Class: rviz_plugins/BusInitialPoseTool - H vehicle height: 3.5 - Interactive: false - L vehicle length: 10.5 - Max velocity: 33.29999923706055 - Min velocity: -33.29999923706055 - Pose Topic: /simulation/dummy_perception_publisher/object_info - Target Frame: - Theta std deviation: 0.0872664600610733 - Velocity: 0 - W vehicle width: 2.5 - X std deviation: 0.029999999329447746 - Y std deviation: 0.029999999329447746 - Z position: 0 - Z std deviation: 0.029999999329447746 - - Class: rviz_plugins/MissionCheckpointTool - Pose Topic: /planning/mission_planning/checkpoint - Theta std deviation: 0.2617993950843811 - X std deviation: 0.5 - Y std deviation: 0.5 - Z position: 0 - - Class: rviz_plugins/DeleteAllObjectsTool - Pose Topic: /simulation/dummy_perception_publisher/object_info - Transformation: - Current: - Class: rviz_default_plugins/TF - Value: true - Views: - Current: - Angle: 0 - Class: rviz_default_plugins/TopDownOrtho - Enable Stereo Rendering: - Stereo Eye Separation: 0.05999999865889549 - Stereo Focal Distance: 1 - Swap Stereo Eyes: false - Value: false - Invert Z Axis: false - Name: Current View - Near Clip Distance: 0.009999999776482582 - Scale: 10 - Target Frame: viewer - Value: TopDownOrtho (rviz_default_plugins) - X: 0 - Y: 0 - Saved: - - Class: rviz_default_plugins/ThirdPersonFollower - Distance: 18 - Enable Stereo Rendering: - Stereo Eye Separation: 0.05999999865889549 - Stereo Focal Distance: 1 - Swap Stereo Eyes: false - Value: false - Focal Point: - X: 0 - Y: 0 - Z: 0 - Focal Shape Fixed Size: true - Focal Shape Size: 0.05000000074505806 - Invert Z Axis: false - Name: ThirdPersonFollower - Near Clip Distance: 0.009999999776482582 - Pitch: 0.20000000298023224 - Target Frame: base_link - Value: ThirdPersonFollower (rviz) - Yaw: 3.141592025756836 - - Angle: 0 - Class: rviz_default_plugins/TopDownOrtho - Enable Stereo Rendering: - Stereo Eye Separation: 0.05999999865889549 - Stereo Focal Distance: 1 - Swap Stereo Eyes: false - Value: false - Invert Z Axis: false - Name: TopDownOrtho - Near Clip Distance: 0.009999999776482582 - Scale: 10 - Target Frame: viewer - Value: TopDownOrtho (rviz) - X: 0 - Y: 0 -Window Geometry: - AutowareDateTimePanel: - collapsed: false - AutowareStatePanel: - collapsed: false - Displays: - collapsed: false - Height: 939 - Hide Left Dock: false - Hide Right Dock: false - PointcloudOnCamera: - collapsed: false - QMainWindow State: 000000ff00000000fd0000000400000000000001ef00000349fc020000000ffb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006b00fffffffb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb00000024004100750074006f00770061007200650053007400610074006500500061006e0065006c01000000440000029b0000008100fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000c00430061006d0065007200610100000682000000eb0000000000000000fb0000000a0049006d0061006700650100000505000002680000000000000000fb0000002c0049006e0069007400690061006c0050006f007300650042007500740074006f006e00500061006e0065006c000000068f000000de0000000000000000fb0000002c0049006e0069007400690061006c0050006f007300650042007500740074006f006e00500061006e0065006c000000068f000000de0000000000000000fb00000030005200650063006f0067006e006900740069006f006e0052006500730075006c0074004f006e0049006d0061006700650000000246000000c10000002c00fffffffb0000002a004100750074006f0077006100720065004400610074006500540069006d006500500061006e0065006c0000000332000000720000004600fffffffb000000240050006f0069006e00740063006c006f00750064004f006e00430061006d006500720061000000039d000000560000002c00fffffffb0000002600530069006d0075006c00610074006500640043006c006f0063006b00500061006e0065006c01000002e6000000a70000007f00ffffff00000001000001ab00000349fc0200000004fb000000100044006900730070006c006100790073010000004400000122000000eb00fffffffc0000016d00000220000000da01000020fa000000000100000002fb0000000a0056006900650077007301000005d5000001ab0000010200fffffffb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000000ffffffff000000a400fffffffb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000e7a0000005afc0100000001fb0000000a00560069006500770073030000004e00000080000002e1000001970000000300000e7a0000005afc0100000002fb0000000800540069006d0065010000000000000e7a0000000000000000fb0000000800540069006d00650100000000000004500000000000000000000003d80000034900000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 - RecognitionResultOnImage: - collapsed: false - Selection: - collapsed: false - SimulatedClockPanel: - collapsed: false - Tool Properties: - collapsed: false - TrafficLightPublishPanel: - collapsed: false - Views: - collapsed: false - Width: 1920 - X: 0 - Y: 34 From 87537bd02e6479e0bb5f95d874822c8e81181c13 Mon Sep 17 00:00:00 2001 From: Masato Saeki <78376491+MasatoSaeki@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:04:13 +0900 Subject: [PATCH 34/61] chore(autoware_traffic_light_occlusion_predictor): modify docs (#9820) * fix docs Signed-off-by: MasatoSaeki * fix docs Signed-off-by: MasatoSaeki --------- Signed-off-by: MasatoSaeki --- .../README.md | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/perception/autoware_traffic_light_occlusion_predictor/README.md b/perception/autoware_traffic_light_occlusion_predictor/README.md index bc57dbea76c97..5d2e320dfc72a 100644 --- a/perception/autoware_traffic_light_occlusion_predictor/README.md +++ b/perception/autoware_traffic_light_occlusion_predictor/README.md @@ -1,8 +1,10 @@ -# The `autoware_traffic_light_occlusion_predictor` Package +# autoware_traffic_light_occlusion_predictor ## Overview `autoware_traffic_light_occlusion_predictor` receives the detected traffic lights rois and calculates the occlusion ratios of each roi with point cloud. +If that rois is judged as occlusion, color, shape, and confidence of `~/output/traffic_signals` become `UNKNOWN`, `UNKNOWN`, and `0.0`. +This node publishes when each car and pedestrian `traffic_signals` is arrived and processed. For each traffic light roi, hundreds of pixels would be selected and projected into the 3D space. Then from the camera point of view, the number of projected pixels that are occluded by the point cloud is counted and used for calculating the occlusion ratio for the roi. As shown in follow image, the red pixels are occluded and the occlusion ratio is the number of red pixels divided by the total pixel numbers. @@ -12,18 +14,20 @@ If no point cloud is received or all point clouds have very large stamp differen ## Input topics -| Name | Type | Description | -| -------------------- | ---------------------------------------------- | ------------------------ | -| `~input/vector_map` | autoware_map_msgs::msg::LaneletMapBin | vector map | -| `~/input/rois` | autoware_perception_msgs::TrafficLightRoiArray | traffic light detections | -| `~input/camera_info` | sensor_msgs::CameraInfo | target camera parameter | -| `~/input/cloud` | sensor_msgs::PointCloud2 | LiDAR point cloud | +| Name | Type | Description | +| ------------------------------------ | ------------------------------------------------ | -------------------------------- | +| `~/input/vector_map` | autoware_map_msgs::msg::LaneletMapBin | vector map | +| `~/input/car/traffic_signals` | tier4_perception_msgs::msg::TrafficLightArray | vehicular traffic light signals | +| `~/input/pedestrian/traffic_signals` | tier4_perception_msgs::msg::TrafficLightArray | pedestrian traffic light signals | +| `~/input/rois` | tier4_perception_msgs::msg::TrafficLightRoiArray | traffic light detections | +| `~/input/camera_info` | sensor_msgs::msg::CameraInfo | target camera parameter | +| `~/input/cloud` | sensor_msgs::msg::PointCloud2 | LiDAR point cloud | ## Output topics -| Name | Type | Description | -| -------------------- | ---------------------------------------------------- | ---------------------------- | -| `~/output/occlusion` | autoware_perception_msgs::TrafficLightOcclusionArray | occlusion ratios of each roi | +| Name | Type | Description | +| -------------------------- | --------------------------------------------- | -------------------------------------------------------------- | +| `~/output/traffic_signals` | tier4_perception_msgs::msg::TrafficLightArray | traffic light signals which occluded image results overwritten | ## Node parameters @@ -34,3 +38,4 @@ If no point cloud is received or all point clouds have very large stamp differen | `max_valid_pt_dist` | double | The points within this distance would be used for calculation | | `max_image_cloud_delay` | double | The maximum delay between LiDAR point cloud and camera image | | `max_wait_t` | double | The maximum time waiting for the LiDAR point cloud | +| `max_occlusion_ratio` | int | The maximum occlusion ratio for setting signal as unknown | From ab6c3b5bd159a723f7ed6836671d370a30929226 Mon Sep 17 00:00:00 2001 From: Masato Saeki <78376491+MasatoSaeki@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:04:27 +0900 Subject: [PATCH 35/61] chore(autoware_traffic_light_multi_camera_fusion): modify docs (#9821) * fix docs Signed-off-by: MasatoSaeki * add condition Signed-off-by: MasatoSaeki --------- Signed-off-by: MasatoSaeki --- .../README.md | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/perception/autoware_traffic_light_multi_camera_fusion/README.md b/perception/autoware_traffic_light_multi_camera_fusion/README.md index f7ee294cda147..b54c623f5d750 100644 --- a/perception/autoware_traffic_light_multi_camera_fusion/README.md +++ b/perception/autoware_traffic_light_multi_camera_fusion/README.md @@ -1,29 +1,36 @@ -# The `traffic_light_multi_camera_fusion` Package +# autoware_traffic_light_multi_camera_fusion ## Overview -`traffic_light_multi_camera_fusion` performs traffic light signal fusion which can be summarized as the following two tasks: +`autoware_traffic_light_multi_camera_fusion` performs traffic light signal fusion which can be summarized as the following two tasks: -1. Multi-Camera-Fusion: performed on single traffic light signal detected by different cameras. -2. Group-Fusion: performed on traffic light signals within the same group, which means traffic lights sharing the same regulatory element id defined in lanelet2 map. +1. Multi-Camera-Fusion: fusion each traffic light signal detected by different cameras. +2. Group-Fusion: Fusion each traffic light signal within the same group, which means traffic lights share the same regulatory element ID defined in lanelet2 map. + +The fusion method is below. + +1. Use the results of the new timestamp if the results are from the same sensor +2. Use the results that are not `elements.size() == 1 && color == UNKNOWN && shape == UNKNOWN` +3. Use the results that each vertex of ROI is not at the edge of the image +4. Use the results of high confidence ## Input topics For every camera, the following three topics are subscribed: -| Name | Type | Description | -| -------------------------------------- | ---------------------------------------------- | --------------------------------------------------- | -| `~//camera_info` | sensor_msgs::CameraInfo | camera info from traffic_light_map_based_detector | -| `~//rois` | tier4_perception_msgs::TrafficLightRoiArray | detection roi from traffic_light_fine_detector | -| `~//traffic_signals` | tier4_perception_msgs::TrafficLightSignalArray | classification result from traffic_light_classifier | +| Name | Type | Description | +| ----------------------------------------------------- | ------------------------------------------------ | ------------------------------------- | +| `~//camera_info` | sensor_msgs::msg::CameraInfo | camera info from map_based_detector | +| `~//detection/rois` | tier4_perception_msgs::msg::TrafficLightRoiArray | detection roi from fine_detector | +| `~//classification/traffic_signals` | tier4_perception_msgs::msg::TrafficLightArray | classification result from classifier | You don't need to configure these topics manually. Just provide the `camera_namespaces` parameter and the node will automatically extract the `` and create the subscribers. ## Output topics -| Name | Type | Description | -| -------------------------- | ------------------------------------------------- | ---------------------------------- | -| `~/output/traffic_signals` | autoware_perception_msgs::TrafficLightSignalArray | traffic light signal fusion result | +| Name | Type | Description | +| -------------------------- | ----------------------------------------------------- | ---------------------------------- | +| `~/output/traffic_signals` | autoware_perception_msgs::msg::TrafficLightGroupArray | traffic light signal fusion result | ## Node parameters From 65f6417db4bf4bda100eb961a841f6d31c94c05b Mon Sep 17 00:00:00 2001 From: Masato Saeki <78376491+MasatoSaeki@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:04:41 +0900 Subject: [PATCH 36/61] chore(autoware_traffic_light_classifier): modify docs (#9819) * modify docs Signed-off-by: MasatoSaeki * style(pre-commit): autofix * fix docs Signed-off-by: MasatoSaeki --------- Signed-off-by: MasatoSaeki Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../README.md | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/perception/autoware_traffic_light_classifier/README.md b/perception/autoware_traffic_light_classifier/README.md index 6e720aabc7593..7dcd4a73380bb 100644 --- a/perception/autoware_traffic_light_classifier/README.md +++ b/perception/autoware_traffic_light_classifier/README.md @@ -1,22 +1,33 @@ -# traffic_light_classifier +# autoware_traffic_light_classifier ## Purpose -traffic_light_classifier is a package for classifying traffic light labels using cropped image around a traffic light. This package has two classifier models: `cnn_classifier` and `hsv_classifier`. +`autoware_traffic_light_classifier` is a package for classifying traffic light labels using cropped image around a traffic light. This package has two classifier models: `cnn_classifier` and `hsv_classifier`. ## Inner-workings / Algorithms +If height and width of `~/input/rois` is `0`, color, shape, and confidence of `~/output/traffic_signals` become `UNKNOWN`, `CIRCLE`, and `0.0`. +If `~/input/rois` is judged as backlight, color, shape, and confidence of `~/output/traffic_signals` become `UNKNOWN`, `UNKNOWN`, and `0.0`. + ### cnn_classifier -Traffic light labels are classified by EfficientNet-b1 or MobileNet-v2. -Totally 83400 (58600 for training, 14800 for evaluation and 10000 for test) TIER IV internal images of Japanese traffic lights were used for fine-tuning. -The information of the models is listed here: +Traffic light labels are classified by EfficientNet-b1 or MobileNet-v2. +We trained classifiers for vehicular signals and pedestrian signals separately. +For vehicular signals, a total of 83400 (58600 for training, 14800 for evaluation and 10000 for test) TIER IV internal images of Japanese traffic lights were used for fine-tuning. | Name | Input Size | Test Accuracy | | --------------- | ---------- | ------------- | | EfficientNet-b1 | 128 x 128 | 99.76% | | MobileNet-v2 | 224 x 224 | 99.81% | +For pedestrian signals, a total of 21199 (17860 for training, 2114 for evaluation and 1225 for test) TIER IV internal images of Japanese traffic lights were used for fine-tuning. +The information of the models is listed here: + +| Name | Input Size | Test Accuracy | +| --------------- | ---------- | ------------- | +| EfficientNet-b1 | 128 x 128 | 97.89% | +| MobileNet-v2 | 224 x 224 | 99.10% | + ### hsv_classifier Traffic light colors (green, yellow and red) are classified in HSV model. @@ -52,11 +63,12 @@ These colors and shapes are assigned to the message as follows: ### Node Parameters -| Name | Type | Description | -| --------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `classifier_type` | int | if the value is `1`, cnn_classifier is used | -| `data_path` | str | packages data and artifacts directory path | -| `backlight_threshold` | float | If the intensity get grater than this overwrite with UNKNOWN in corresponding RoI. Note that, if the value is much higher, the node only overwrites in the harsher backlight situations. Therefore, If you wouldn't like to use this feature set this value to `1.0`. The value can be `[0.0, 1.0]`. The confidence of overwritten signal is set to `0.0`. | +| Name | Type | Description | +| ----------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `classifier_type` | int | If the value is `1`, cnn_classifier is used | +| `data_path` | str | Packages data and artifacts directory path | +| `backlight_threshold` | double | If the intensity of light is grater than this threshold, the color and shape of the corresponding ROI will be overwritten with UNKNOWN, and the confidence of the overwritten signal will be set to `0.0`. The value should be set in the range of `[0.0, 1.0]`. If you wouldn't like to use this feature, please set it to `1.0`. | +| `classify_traffic_light_type` | int | If the value is `0`, vehicular signals are classified. If the value is `1`, pedestrian signals are classified. | ### Core Parameters From b69241f6659c042a05bc9362c3d254e25fbaa290 Mon Sep 17 00:00:00 2001 From: Masato Saeki <78376491+MasatoSaeki@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:04:56 +0900 Subject: [PATCH 37/61] chore(autoware_crosswalk_traffic_light_estimator): fix docs (#9822) * fix docs Signed-off-by: MasatoSaeki * fix docs Signed-off-by: MasatoSaeki * add tlr output image Signed-off-by: MasatoSaeki * modify sentense Signed-off-by: MasatoSaeki * modify sentense Signed-off-by: MasatoSaeki * refactor readme Signed-off-by: MasatoSaeki * fix docs Signed-off-by: MasatoSaeki * fix Signed-off-by: MasatoSaeki * style(pre-commit): autofix --------- Signed-off-by: MasatoSaeki Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../README.md | 81 ++++++++++++++---- .../images/flashing_state.png | Bin 0 -> 24574 bytes .../images/traffic_light.png | Bin 0 -> 54297 bytes 3 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 perception/autoware_crosswalk_traffic_light_estimator/images/flashing_state.png create mode 100644 perception/autoware_crosswalk_traffic_light_estimator/images/traffic_light.png diff --git a/perception/autoware_crosswalk_traffic_light_estimator/README.md b/perception/autoware_crosswalk_traffic_light_estimator/README.md index b14fefbd43beb..1b24b115f5812 100644 --- a/perception/autoware_crosswalk_traffic_light_estimator/README.md +++ b/perception/autoware_crosswalk_traffic_light_estimator/README.md @@ -1,40 +1,85 @@ -# crosswalk_traffic_light_estimator +# autoware_crosswalk_traffic_light_estimator ## Purpose -`crosswalk_traffic_light_estimator` is a module that estimates pedestrian traffic signals from HDMap and detected vehicle traffic signals. +`autoware_crosswalk_traffic_light_estimator` estimates pedestrian traffic signals which can be summarized as the following two tasks: + +- Estimate pedestrian traffic signals that are not subject to be detected by perception pipeline. +- Estimate whether pedestrian traffic signals are flashing and modify the result. + +This module works without `~/input/route`, but its behavior is outputting the subscribed results as is. ## Inputs / Outputs ### Input -| Name | Type | Description | -| ------------------------------------ | ------------------------------------------------ | ------------------ | -| `~/input/vector_map` | `autoware_map_msgs::msg::LaneletMapBin` | vector map | -| `~/input/route` | `autoware_planning_msgs::msg::LaneletRoute` | route | -| `~/input/classified/traffic_signals` | `tier4_perception_msgs::msg::TrafficSignalArray` | classified signals | +| Name | Type | Description | +| ------------------------------------ | ----------------------------------------------------- | ------------------ | +| `~/input/vector_map` | autoware_map_msgs::msg::LaneletMapBin | vector map | +| `~/input/route` | autoware_planning_msgs::msg::LaneletRoute | optional: route | +| `~/input/classified/traffic_signals` | autoware_perception_msgs::msg::TrafficLightGroupArray | classified signals | ### Output -| Name | Type | Description | -| -------------------------- | ------------------------------------------------------- | --------------------------------------------------------- | -| `~/output/traffic_signals` | `autoware_perception_msgs::msg::TrafficLightGroupArray` | output that contains estimated pedestrian traffic signals | +| Name | Type | Description | +| -------------------------- | ----------------------------------------------------- | --------------------------------------------------------- | +| `~/output/traffic_signals` | autoware_perception_msgs::msg::TrafficLightGroupArray | output that contains estimated pedestrian traffic signals | ## Parameters -| Name | Type | Description | Default value | -| :---------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------ | -| `use_last_detect_color` | `bool` | If this parameter is `true`, this module estimates pedestrian's traffic signal as RED not only when vehicle's traffic signal is detected as GREEN/AMBER but also when detection results change GREEN/AMBER to UNKNOWN. (If detection results change RED or AMBER to UNKNOWN, this module estimates pedestrian's traffic signal as UNKNOWN.) If this parameter is `false`, this module use only latest detection results for estimation. (Only when the detection result is GREEN/AMBER, this module estimates pedestrian's traffic signal as RED.) | `true` | -| `last_detect_color_hold_time` | `double` | The time threshold to hold for last detect color. | `2.0` | +| Name | Type | Description | Default value | +| :---------------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------ | +| `use_last_detect_color` | bool | If this parameter is `true`, this module estimates pedestrian's traffic signal as RED not only when vehicle's traffic signal is detected as GREEN/AMBER but also when detection results change GREEN/AMBER to UNKNOWN. (If detection results change RED or AMBER to UNKNOWN, this module estimates pedestrian's traffic signal as UNKNOWN.) If this parameter is `false`, this module use only latest detection results for estimation. (Only when the detection result is GREEN/AMBER, this module estimates pedestrian's traffic signal as RED.) | true | +| `last_detect_color_hold_time` | double | The time threshold to hold for last detect color. The unit is second. | 2.0 | +| `last_colors_hold_time` | double | The time threshold to hold for history detected pedestrian traffic light color. The unit is second. | 1.0 | ## Inner-workings / Algorithms +When the pedestrian traffic signals **are detected** by perception pipeline + +- If estimates the pedestrian traffic signals are flashing, overwrite the results +- Prefer the output from perception pipeline, but overwrite it if the pedestrian traffic signals are invalid(`no detection`, `backlight`, or `occlusion`) + +When the pedestrian traffic signals **are NOT detected** by perception pipeline + +- Estimate the color of pedestrian traffic signals based on detected vehicle traffic signals, HDMap, and route + +### Estimate whether pedestrian traffic signals are flashing + +```plantumul +start +if (the pedestrian traffic light classification result exists)then + : update the flashing flag according to the classification result(in_signal) and last_signals + if (the traffic light is flashing?)then(yes) + : update the traffic light state + else(no) + : the traffic light state is the same with the classification result +if (the classification result not exists) + : the traffic light state is the same with the estimation + : output the current traffic light state +end +``` + +#### Update flashing flag + +

+ +
+ +#### Update traffic light status + +
+ +
+ +### Estimate the color of pedestrian traffic signals + ```plantuml start -:subscribe detected traffic signals & HDMap; +:subscribe detected traffic signals, HDMap, and route; :extract crosswalk lanelets from HDMap; -:extract road lanelets that conflicts crosswalk; +:extract road lanelets that conflicts crosswalk from route; :initialize non_red_lanelets(lanelet::ConstLanelets); if (Latest detection result is **GREEN** or **AMBER**?) then (yes) :push back non_red_lanelets; @@ -58,7 +103,7 @@ end If traffic between pedestrians and vehicles is controlled by traffic signals, the crosswalk traffic signal maybe **RED** in order to prevent pedestrian from crossing when the following conditions are satisfied. -### Situation1 +#### Situation1 - crosswalk conflicts **STRAIGHT** lanelet - the lanelet refers **GREEN** or **AMBER** traffic signal (The following pictures show only **GREEN** case) @@ -70,7 +115,7 @@ If traffic between pedestrians and vehicles is controlled by traffic signals, th -### Situation2 +#### Situation2 - crosswalk conflicts different turn direction lanelets (STRAIGHT and LEFT, LEFT and RIGHT, RIGHT and STRAIGHT) - the lanelets refer **GREEN** or **AMBER** traffic signal (The following pictures show only **GREEN** case) diff --git a/perception/autoware_crosswalk_traffic_light_estimator/images/flashing_state.png b/perception/autoware_crosswalk_traffic_light_estimator/images/flashing_state.png new file mode 100644 index 0000000000000000000000000000000000000000..7686f3842e75c92cfd27f9de08ef1ecf6eb3651f GIT binary patch literal 24574 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⁣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�qx~ik1hIyx34MrGbm-3 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 literal 0 HcmV?d00001 From a2755a4926c41618c2fbd4da41324f46cca0b7f8 Mon Sep 17 00:00:00 2001 From: Ryuta Kambe Date: Thu, 16 Jan 2025 10:01:43 +0900 Subject: [PATCH 38/61] fix(mrm_handler): simplify hazard command choice (#9929) Signed-off-by: Ryuta Kambe --- system/mrm_handler/src/mrm_handler/mrm_handler_core.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/system/mrm_handler/src/mrm_handler/mrm_handler_core.cpp b/system/mrm_handler/src/mrm_handler/mrm_handler_core.cpp index 4022bdaadebef..b5f4bbaeefc46 100644 --- a/system/mrm_handler/src/mrm_handler/mrm_handler_core.cpp +++ b/system/mrm_handler/src/mrm_handler/mrm_handler_core.cpp @@ -115,12 +115,7 @@ void MrmHandler::publishHazardCmd() HazardLightsCommand msg; msg.stamp = this->now(); - if (is_emergency_holding_) { - // turn hazard on during emergency holding - msg.command = HazardLightsCommand::ENABLE; - } else if (isEmergency() && param_.turning_hazard_on.emergency) { - // turn hazard on if vehicle is in emergency state and - // turning hazard on if emergency flag is true + if (param_.turning_hazard_on.emergency && isEmergency()) { msg.command = HazardLightsCommand::ENABLE; } else { msg.command = HazardLightsCommand::NO_COMMAND; From 347a2e48109452c70447ce219a207b5fd75591f1 Mon Sep 17 00:00:00 2001 From: Kosuke Takeuchi Date: Thu, 16 Jan 2025 13:34:45 +0900 Subject: [PATCH 39/61] fix(goal_planner): fix geometric pull over (#9932) Signed-off-by: kosuke55 --- .../src/pull_over_planner/geometric_pull_over.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp index bf2ce86b49bab..44dca13ccfd66 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp @@ -28,6 +28,7 @@ namespace autoware::behavior_path_planner GeometricPullOver::GeometricPullOver( rclcpp::Node & node, const GoalPlannerParameters & parameters, const bool is_forward) : PullOverPlannerBase{node, parameters}, + parallel_parking_parameters_{parameters.parallel_parking_parameters}, lane_departure_checker_{ lane_departure_checker::Param{parameters.lane_departure_check_expansion_margin}, vehicle_info_}, is_forward_{is_forward}, From e09193784833044b8597c4d3dd7dda9bf169de74 Mon Sep 17 00:00:00 2001 From: mkquda <168697710+mkquda@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:51:37 +0900 Subject: [PATCH 40/61] feat(lane_change): ensure path generation doesn't exceed time limit (#9908) * add time limit for lane change candidate path generation Signed-off-by: mohammad alqudah * apply time limit for frenet method as well Signed-off-by: mohammad alqudah * ensure param update value is valid Signed-off-by: mohammad alqudah * fix param update initial value Signed-off-by: mohammad alqudah * fix spelling Signed-off-by: mohammad alqudah * fix param update initial values Signed-off-by: mohammad alqudah --------- Signed-off-by: mohammad alqudah --- .../README.md | 1 + .../config/lane_change.param.yaml | 1 + .../structs/parameters.hpp | 1 + .../src/manager.cpp | 52 +++++++++++++------ .../src/scene.cpp | 18 +++++-- 5 files changed, 52 insertions(+), 21 deletions(-) diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md index ee371f8592833..20fd564049133 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md @@ -1039,6 +1039,7 @@ The following parameters are configurable in [lane_change.param.yaml](https://gi | Name | Unit | Type | Description | Default value | | :------------------------------------------- | ------ | ------ | ---------------------------------------------------------------------------------------------------------------------- | ------------------ | +| `time_limit` | [ms] | double | Time limit for lane change candidate path generation | 50.0 | | `backward_lane_length` | [m] | double | The backward length to check incoming objects in lane change target lane. | 200.0 | | `backward_length_buffer_for_end_of_lane` | [m] | double | The end of lane buffer to ensure ego vehicle has enough distance to start lane change | 3.0 | | `backward_length_buffer_for_blocking_object` | [m] | double | The end of lane buffer to ensure ego vehicle has enough distance to start lane change when there is an object in front | 3.0 | diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml index df9491576a4ee..15eb23daecf95 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml @@ -1,6 +1,7 @@ /**: ros__parameters: lane_change: + time_limit: 50.0 # [ms] backward_lane_length: 200.0 backward_length_buffer_for_end_of_lane: 3.0 # [m] backward_length_buffer_for_blocking_object: 3.0 # [m] diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp index f0adcb1d69b42..60386f535fc64 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp @@ -162,6 +162,7 @@ struct Parameters FrenetPlannerParameters frenet{}; // lane change parameters + double time_limit{50.0}; double backward_lane_length{200.0}; double backward_length_buffer_for_end_of_lane{0.0}; double backward_length_buffer_for_blocking_object{0.0}; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp index 07b05ab0ea131..f26cf79e8b120 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp @@ -190,6 +190,7 @@ LCParamPtr LaneChangeModuleManager::set_params(rclcpp::Node * node, const std::s } // lane change parameters + p.time_limit = getOrDeclareParameter(*node, parameter("time_limit")); p.backward_lane_length = getOrDeclareParameter(*node, parameter("backward_lane_length")); p.backward_length_buffer_for_end_of_lane = getOrDeclareParameter(*node, parameter("backward_length_buffer_for_end_of_lane")); @@ -313,6 +314,17 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectortime_limit; + updateParam(parameters, ns + "time_limit", time_limit); + if (time_limit >= 10.0) { + p->time_limit = time_limit; + } else { + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, + "WARNING! Parameter 'time_limit' is not updated because the value (%.3f ms) is not valid, " + "keep current value (%.3f ms)", + time_limit, p->time_limit); + } updateParam(parameters, ns + "backward_lane_length", p->backward_lane_length); updateParam( parameters, ns + "backward_length_buffer_for_end_of_lane", @@ -349,25 +361,27 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectortrajectory.lane_changing_decel_factor); updateParam( parameters, ns + "th_prepare_curvature", p->trajectory.th_prepare_curvature); - int longitudinal_acc_sampling_num = 0; + int longitudinal_acc_sampling_num = p->trajectory.lon_acc_sampling_num; updateParam(parameters, ns + "lon_acc_sampling_num", longitudinal_acc_sampling_num); if (longitudinal_acc_sampling_num > 0) { p->trajectory.lon_acc_sampling_num = longitudinal_acc_sampling_num; } else { - RCLCPP_WARN_ONCE( - node_->get_logger(), - "Parameter 'lon_acc_sampling_num' is not updated because the value (%d) is not positive", + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, + "WARNING! Parameter 'lon_acc_sampling_num' is not updated because the value (%d) is not " + "positive", longitudinal_acc_sampling_num); } - int lateral_acc_sampling_num = 0; + int lateral_acc_sampling_num = p->trajectory.lat_acc_sampling_num; updateParam(parameters, ns + "lat_acc_sampling_num", lateral_acc_sampling_num); if (lateral_acc_sampling_num > 0) { p->trajectory.lat_acc_sampling_num = lateral_acc_sampling_num; } else { - RCLCPP_WARN_ONCE( - node_->get_logger(), - "Parameter 'lat_acc_sampling_num' is not updated because the value (%d) is not positive", + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, + "WARNING! Parameter 'lat_acc_sampling_num' is not updated because the value (%d) is not " + "positive", lateral_acc_sampling_num); } @@ -409,8 +423,8 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectortrajectory.lat_acc_map = lat_acc_map; } else { - RCLCPP_WARN_ONCE( - node_->get_logger(), + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, "Mismatched size for lateral acceleration. Expected size: %lu, but velocity: %lu, " "min_values: %lu, max_values: %lu", std::max(2ul, velocity.size()), velocity.size(), min_values.size(), max_values.size()); @@ -515,28 +529,32 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectorcancel.enable_on_prepare_phase; updateParam(parameters, ns + "enable_on_prepare_phase", enable_on_prepare_phase); if (!enable_on_prepare_phase) { - RCLCPP_WARN_ONCE(node_->get_logger(), "WARNING! Lane Change cancel function is disabled."); + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, + "WARNING! Lane Change cancel function is disabled."); p->cancel.enable_on_prepare_phase = enable_on_prepare_phase; } - bool enable_on_lane_changing_phase = true; + bool enable_on_lane_changing_phase = p->cancel.enable_on_lane_changing_phase; updateParam( parameters, ns + "enable_on_lane_changing_phase", enable_on_lane_changing_phase); if (!enable_on_lane_changing_phase) { - RCLCPP_WARN_ONCE(node_->get_logger(), "WARNING! Lane Change abort function is disabled."); + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, + "WARNING! Lane Change abort function is disabled."); p->cancel.enable_on_lane_changing_phase = enable_on_lane_changing_phase; } - int deceleration_sampling_num = 0; + int deceleration_sampling_num = p->cancel.deceleration_sampling_num; updateParam(parameters, ns + "deceleration_sampling_num", deceleration_sampling_num); if (deceleration_sampling_num > 0) { p->cancel.deceleration_sampling_num = deceleration_sampling_num; } else { - RCLCPP_WARN_ONCE( - node_->get_logger(), + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, "Parameter 'deceleration_sampling_num' is not updated because the value (%d) is not " "positive", deceleration_sampling_num); diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp index 7748795851865..45fcd6fa99086 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp @@ -1154,18 +1154,22 @@ bool NormalLaneChange::get_path_using_frenet( const std::vector> & sorted_lane_ids, LaneChangePaths & candidate_paths) const { - stop_watch_.tic("frenet_candidates"); + stop_watch_.tic(__func__); constexpr auto found_safe_path = true; const auto frenet_candidates = utils::lane_change::generate_frenet_candidates( common_data_ptr_, prev_module_output_.path, prepare_metrics); RCLCPP_DEBUG( logger_, "Generated %lu candidate paths in %2.2f[us]", frenet_candidates.size(), - stop_watch_.toc("frenet_candidates")); + stop_watch_.toc(__func__)); candidate_paths.reserve(frenet_candidates.size()); lane_change_debug_.frenet_states.clear(); lane_change_debug_.frenet_states.reserve(frenet_candidates.size()); for (const auto & frenet_candidate : frenet_candidates) { + if (stop_watch_.toc(__func__) >= lane_change_parameters_->time_limit) { + break; + } + lane_change_debug_.frenet_states.emplace_back( frenet_candidate.prepare_metric, frenet_candidate.lane_changing.sampling_parameter, frenet_candidate.max_lane_changing_length); @@ -1186,7 +1190,7 @@ bool NormalLaneChange::get_path_using_frenet( if (check_candidate_path_safety(*candidate_path_opt, target_objects)) { RCLCPP_DEBUG( logger_, "Found safe path after %lu candidate(s). Total time: %2.2f[us]", - frenet_candidates.size(), stop_watch_.toc("frenet_candidates")); + frenet_candidates.size(), stop_watch_.toc("__func__")); utils::lane_change::append_target_ref_to_candidate( *candidate_path_opt, common_data_ptr_->lc_param_ptr->frenet.th_curvature_smoothing); candidate_paths.push_back(*candidate_path_opt); @@ -1204,7 +1208,7 @@ bool NormalLaneChange::get_path_using_frenet( RCLCPP_DEBUG( logger_, "No safe path after %lu candidate(s). Total time: %2.2f[us]", frenet_candidates.size(), - stop_watch_.toc("frenet_candidates")); + stop_watch_.toc(__func__)); return !found_safe_path; } @@ -1214,6 +1218,7 @@ bool NormalLaneChange::get_path_using_path_shifter( const std::vector> & sorted_lane_ids, LaneChangePaths & candidate_paths) const { + stop_watch_.tic(__func__); const auto & target_lanes = get_target_lanes(); candidate_paths.reserve( prepare_metrics.size() * lane_change_parameters_->trajectory.lat_acc_sampling_num); @@ -1279,6 +1284,11 @@ bool NormalLaneChange::get_path_using_path_shifter( prepare_segment, common_data_ptr_->get_ego_speed(), prep_metric.velocity); for (const auto & lc_metric : lane_changing_metrics) { + if (stop_watch_.toc(__func__) >= lane_change_parameters_->time_limit) { + RCLCPP_DEBUG(logger_, "Time limit reached and no safe path was found."); + return false; + } + debug_metrics.lc_metrics.emplace_back(lc_metric, -1); const auto debug_print_lat = [&](const std::string & s) { From 099591a740cec19de99c4590f7b468ab9e1d5572 Mon Sep 17 00:00:00 2001 From: Fumiya Watanabe Date: Thu, 16 Jan 2025 14:01:58 +0900 Subject: [PATCH 41/61] chore(simple_planning_simulator): add maintainer (#9934) --- .github/CODEOWNERS | 2 +- simulator/simple_planning_simulator/package.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5bbc4d1c6177b..4fea7c85e1926 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -204,7 +204,7 @@ simulator/autoware_carla_interface/** maxime.clement@tier4.jp mradityagio@gmail. simulator/dummy_perception_publisher/** yukihiro.saito@tier4.jp simulator/fault_injection/** keisuke.shima@tier4.jp simulator/learning_based_vehicle_model/** maxime.clement@tier4.jp nagy.tomas@tier4.jp -simulator/simple_planning_simulator/** mamoru.sobue@tier4.jp maxime.clement@tier4.jp takamasa.horibe@tier4.jp temkei.kem@tier4.jp tomoya.kimura@tier4.jp zulfaqar.azmi@tier4.jp +simulator/simple_planning_simulator/** mamoru.sobue@tier4.jp maxime.clement@tier4.jp takamasa.horibe@tier4.jp temkei.kem@tier4.jp tomoya.kimura@tier4.jp zulfaqar.azmi@tier4.jp kotaro.yoshimoto@tier4.jp simulator/tier4_dummy_object_rviz_plugin/** yukihiro.saito@tier4.jp simulator/vehicle_door_simulator/** isamu.takagi@tier4.jp system/autoware_component_monitor/** baris@leodrive.ai memin@leodrive.ai yavuz@leodrive.ai diff --git a/simulator/simple_planning_simulator/package.xml b/simulator/simple_planning_simulator/package.xml index fdc782182f9a5..5bd7a2f74eacc 100644 --- a/simulator/simple_planning_simulator/package.xml +++ b/simulator/simple_planning_simulator/package.xml @@ -10,6 +10,7 @@ Mamoru Sobue Zulfaqar Azmi Temkei Kem + Kotaro Yoshimoto Apache License 2.0 ament_cmake_auto From 01a764782c86e614a27808b973d073c12da2217e Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:23:18 +0900 Subject: [PATCH 42/61] feat(autoware_shape_estimation): tier4_debug_msgs chnaged to autoware_internal_debug_msgs in autoware_shape_estimation (#9897) feat: tier4_debug_msgs chnaged to autoware_internal_debug_msgs in files perception/autoware_shape_estimation Signed-off-by: vish0012 --- .../autoware_shape_estimation/src/shape_estimation_node.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perception/autoware_shape_estimation/src/shape_estimation_node.cpp b/perception/autoware_shape_estimation/src/shape_estimation_node.cpp index c5450dc14adb0..28b2a6e398e91 100644 --- a/perception/autoware_shape_estimation/src/shape_estimation_node.cpp +++ b/perception/autoware_shape_estimation/src/shape_estimation_node.cpp @@ -179,9 +179,9 @@ void ShapeEstimationNode::callback(const DetectedObjectsWithFeature::ConstShared // Publish pub_->publish(output_msg); published_time_publisher_->publish_if_subscribed(pub_, output_msg.header.stamp); - processing_time_publisher_->publish( + processing_time_publisher_->publish( "debug/cyclic_time_ms", stop_watch_ptr_->toc("cyclic_time", true)); - processing_time_publisher_->publish( + processing_time_publisher_->publish( "debug/processing_time_ms", stop_watch_ptr_->toc("processing_time", true)); } } // namespace autoware::shape_estimation From 415e1ec0bc0e1a7f446c664f4161a1219f48ca36 Mon Sep 17 00:00:00 2001 From: Takayuki Murooka Date: Thu, 16 Jan 2025 17:27:22 +0900 Subject: [PATCH 43/61] fix: remove unnecessary parameters (#9935) Signed-off-by: Takayuki Murooka --- .../autoware_pid_longitudinal_controller/README.md | 2 -- .../param/lateral/mpc.param.yaml | 2 -- .../param/longitudinal/pid.param.yaml | 2 -- .../config/crosswalk.param.yaml | 2 -- .../README.md | 13 ++++++------- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/control/autoware_pid_longitudinal_controller/README.md b/control/autoware_pid_longitudinal_controller/README.md index aba0f36f04d65..957379866b62a 100644 --- a/control/autoware_pid_longitudinal_controller/README.md +++ b/control/autoware_pid_longitudinal_controller/README.md @@ -195,8 +195,6 @@ AutonomouStuff Lexus RX 450h for under 40 km/h driving. | stopped_state_entry_vel | double | threshold of the ego velocity in transition to the STOPPED state [m/s] | 0.01 | | stopped_state_entry_acc | double | threshold of the ego acceleration in transition to the STOPPED state [m/s^2] | 0.1 | | emergency_state_overshoot_stop_dist | double | If `enable_overshoot_emergency` is true and the ego is `emergency_state_overshoot_stop_dist`-meter ahead of the stop point, the state will transit to EMERGENCY. [m] | 1.5 | -| emergency_state_traj_trans_dev | double | If the ego's position is `emergency_state_traj_tran_dev` meter away from the nearest trajectory point, the state will transit to EMERGENCY. [m] | 3.0 | -| emergency_state_traj_rot_dev | double | If the ego's orientation is `emergency_state_traj_rot_dev` rad away from the nearest trajectory point orientation, the state will transit to EMERGENCY. [rad] | 0.784 | ### DRIVE Parameter diff --git a/control/autoware_trajectory_follower_node/param/lateral/mpc.param.yaml b/control/autoware_trajectory_follower_node/param/lateral/mpc.param.yaml index b358e95f86f99..1d30a28d05cb8 100644 --- a/control/autoware_trajectory_follower_node/param/lateral/mpc.param.yaml +++ b/control/autoware_trajectory_follower_node/param/lateral/mpc.param.yaml @@ -3,8 +3,6 @@ # -- system -- traj_resample_dist: 0.1 # path resampling interval [m] use_steer_prediction: false # flag for using steer prediction (do not use steer measurement) - admissible_position_error: 5.0 # stop mpc calculation when error is larger than the following value - admissible_yaw_error_rad: 1.57 # stop mpc calculation when error is larger than the following value use_delayed_initial_state: true # flag to use x0_delayed as initial state for predicted trajectory # -- path smoothing -- diff --git a/control/autoware_trajectory_follower_node/param/longitudinal/pid.param.yaml b/control/autoware_trajectory_follower_node/param/longitudinal/pid.param.yaml index 5c5d65a13b2d5..f3139308db37c 100644 --- a/control/autoware_trajectory_follower_node/param/longitudinal/pid.param.yaml +++ b/control/autoware_trajectory_follower_node/param/longitudinal/pid.param.yaml @@ -16,8 +16,6 @@ stopped_state_entry_vel: 0.01 stopped_state_entry_acc: 0.1 emergency_state_overshoot_stop_dist: 1.5 - emergency_state_traj_trans_dev: 3.0 - emergency_state_traj_rot_dev: 0.7854 # drive state kp: 1.0 diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/config/crosswalk.param.yaml b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/config/crosswalk.param.yaml index bc0d4f613f10b..97e00ade8256c 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/config/crosswalk.param.yaml +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/config/crosswalk.param.yaml @@ -13,8 +13,6 @@ # For the Lanelet2 map with no explicit stop lines stop_distance_from_crosswalk: 3.5 # [m] make stop line away from crosswalk - # For the case where the crosswalk width is very wide - far_object_threshold: 10.0 # [m] If objects cross X meters behind the stop line, the stop position is determined according to the object position (stop_distance_from_object meters before the object). # For the case where the stop position is determined according to the object position. stop_distance_from_object_preferred: 3.0 # [m] stop_distance_from_object_limit: 3.0 # [m] diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/README.md b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/README.md index efe4a9a353ecc..963d75e5a8492 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/README.md +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/README.md @@ -12,13 +12,12 @@ This module is activated when there is a stop line in a target lane. ## Module Parameters -| Parameter | Type | Description | -| -------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `stop_margin` | double | Margin that the vehicle tries to stop in before stop_line | -| `stop_duration_sec` | double | [s] Time parameter for the ego vehicle to stop before stop line | -| `hold_stop_margin_distance` | double | [m] Parameter for restart prevention (See Algorithm section). Also, when the ego vehicle is within this distance from a stop line, the ego state becomes STOPPED from APPROACHING | -| `use_initialization_stop_state` | bool | Flag to determine whether to return to the approaching state when the vehicle moves away from a stop line. | -| `show_stop_line_collision_check` | bool | Flag to determine whether to show the debug information of collision check with a stop line | +| Parameter | Type | Description | +| ------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `stop_margin` | double | Margin that the vehicle tries to stop in before stop_line | +| `stop_duration_sec` | double | [s] Time parameter for the ego vehicle to stop before stop line | +| `hold_stop_margin_distance` | double | [m] Parameter for restart prevention (See Algorithm section). Also, when the ego vehicle is within this distance from a stop line, the ego state becomes STOPPED from APPROACHING | +| `use_initialization_stop_state` | bool | Flag to determine whether to return to the approaching state when the vehicle moves away from a stop line. | ## Inner-workings / Algorithms From cb33b74ccd35b9b29bc11daf83209d9db72c6ab4 Mon Sep 17 00:00:00 2001 From: Takayuki Murooka Date: Thu, 16 Jan 2025 17:27:46 +0900 Subject: [PATCH 44/61] feat(velocity_smoother): introduce diagnostics (#9933) * feat(velocity_smoother): introduce diagnostics Signed-off-by: Takayuki Murooka * fix Signed-off-by: Takayuki Murooka --------- Signed-off-by: Takayuki Murooka --- .../include/autoware/velocity_smoother/node.hpp | 11 ++++++----- .../autoware_velocity_smoother/src/node.cpp | 17 +++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/planning/autoware_velocity_smoother/include/autoware/velocity_smoother/node.hpp b/planning/autoware_velocity_smoother/include/autoware/velocity_smoother/node.hpp index fc0066b1a84f3..d519356c7aa18 100644 --- a/planning/autoware_velocity_smoother/include/autoware/velocity_smoother/node.hpp +++ b/planning/autoware_velocity_smoother/include/autoware/velocity_smoother/node.hpp @@ -20,6 +20,7 @@ #include "autoware/osqp_interface/osqp_interface.hpp" #include "autoware/universe_utils/geometry/geometry.hpp" #include "autoware/universe_utils/math/unit_conversion.hpp" +#include "autoware/universe_utils/ros/diagnostics_interface.hpp" #include "autoware/universe_utils/ros/logger_level_configure.hpp" #include "autoware/universe_utils/ros/polling_subscriber.hpp" #include "autoware/universe_utils/ros/self_pose_listener.hpp" @@ -45,8 +46,7 @@ #include "autoware_planning_msgs/msg/trajectory_point.hpp" #include "geometry_msgs/msg/accel_with_covariance_stamped.hpp" #include "nav_msgs/msg/odometry.hpp" -#include "tier4_planning_msgs/msg/stop_speed_exceeded.hpp" // temporary -#include "tier4_planning_msgs/msg/velocity_limit.hpp" // temporary +#include "tier4_planning_msgs/msg/velocity_limit.hpp" // temporary #include "visualization_msgs/msg/marker_array.hpp" #include @@ -61,6 +61,7 @@ namespace autoware::velocity_smoother using autoware_planning_msgs::msg::Trajectory; using autoware_planning_msgs::msg::TrajectoryPoint; using TrajectoryPoints = std::vector; +using autoware::universe_utils::DiagnosticsInterface; using autoware_adapi_v1_msgs::msg::OperationModeState; using autoware_internal_debug_msgs::msg::Float32Stamped; using autoware_internal_debug_msgs::msg::Float64Stamped; @@ -68,8 +69,7 @@ using geometry_msgs::msg::AccelWithCovarianceStamped; using geometry_msgs::msg::Pose; using geometry_msgs::msg::PoseStamped; using nav_msgs::msg::Odometry; -using tier4_planning_msgs::msg::StopSpeedExceeded; // temporary -using tier4_planning_msgs::msg::VelocityLimit; // temporary +using tier4_planning_msgs::msg::VelocityLimit; // temporary using visualization_msgs::msg::MarkerArray; struct Motion @@ -89,7 +89,6 @@ class VelocitySmootherNode : public rclcpp::Node private: rclcpp::Publisher::SharedPtr pub_trajectory_; rclcpp::Publisher::SharedPtr pub_virtual_wall_; - rclcpp::Publisher::SharedPtr pub_over_stop_velocity_; rclcpp::Subscription::SharedPtr sub_current_trajectory_; autoware::universe_utils::InterProcessPollingSubscriber sub_current_odometry_{ this, "/localization/kinematic_state"}; @@ -290,6 +289,8 @@ class VelocitySmootherNode : public rclcpp::Node std::unique_ptr published_time_publisher_; mutable std::shared_ptr time_keeper_{nullptr}; + + std::unique_ptr diagnostics_interface_{nullptr}; }; } // namespace autoware::velocity_smoother diff --git a/planning/autoware_velocity_smoother/src/node.cpp b/planning/autoware_velocity_smoother/src/node.cpp index 1e0f6119ac21e..1f2b1cad6e42a 100644 --- a/planning/autoware_velocity_smoother/src/node.cpp +++ b/planning/autoware_velocity_smoother/src/node.cpp @@ -36,7 +36,8 @@ namespace autoware::velocity_smoother { VelocitySmootherNode::VelocitySmootherNode(const rclcpp::NodeOptions & node_options) -: Node("velocity_smoother", node_options) +: Node("velocity_smoother", node_options), + diagnostics_interface_(std::make_unique(this, "velocity_smoother")) { using std::placeholders::_1; @@ -63,7 +64,6 @@ VelocitySmootherNode::VelocitySmootherNode(const rclcpp::NodeOptions & node_opti pub_velocity_limit_ = create_publisher( "~/output/current_velocity_limit_mps", rclcpp::QoS{1}.transient_local()); pub_dist_to_stopline_ = create_publisher("~/distance_to_stopline", 1); - pub_over_stop_velocity_ = create_publisher("~/stop_speed_exceeded", 1); sub_current_trajectory_ = create_subscription( "~/input/trajectory", 1, std::bind(&VelocitySmootherNode::onCurrentTrajectory, this, _1)); @@ -444,6 +444,7 @@ void VelocitySmootherNode::onCurrentTrajectory(const Trajectory::ConstSharedPtr RCLCPP_DEBUG(get_logger(), "========================= run start ========================="); stop_watch_.tic(); + diagnostics_interface_->clear(); base_traj_raw_ptr_ = msg; // receive data @@ -524,6 +525,10 @@ void VelocitySmootherNode::onCurrentTrajectory(const Trajectory::ConstSharedPtr // Publish Calculation Time publishStopWatchTime(); + + // Publish diagnostics + diagnostics_interface_->publish(now()); + RCLCPP_DEBUG(get_logger(), "========================== run() end ==========================\n\n"); } @@ -906,12 +911,8 @@ void VelocitySmootherNode::overwriteStopPoint( input_stop_vel, output_stop_vel, over_stop_velocity_warn_thr_); } - { - StopSpeedExceeded msg{}; - msg.stamp = this->now(); - msg.stop_speed_exceeded = is_stop_velocity_exceeded; - pub_over_stop_velocity_->publish(msg); - } + diagnostics_interface_->add_key_value( + "The velocity on the stop point is larger than 0.", is_stop_velocity_exceeded); } void VelocitySmootherNode::applyExternalVelocityLimit(TrajectoryPoints & traj) const From ed1f844ce77f496cc44894d23492646354a12217 Mon Sep 17 00:00:00 2001 From: Kyoichi Sugahara <32741405+kyoichi-sugahara@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:36:00 +0900 Subject: [PATCH 45/61] test(start_planner): disable GenerateValidFreespacePullOutPath test (#9937) Signed-off-by: kyoichi-sugahara --- .../test/test_freespace_pull_out.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/test/test_freespace_pull_out.cpp b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/test/test_freespace_pull_out.cpp index 79c58c37f0dcf..5078c463d7c36 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/test/test_freespace_pull_out.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/test/test_freespace_pull_out.cpp @@ -78,7 +78,7 @@ class TestFreespacePullOut : public ::testing::Test } }; -TEST_F(TestFreespacePullOut, GenerateValidFreespacePullOutPath) +TEST_F(TestFreespacePullOut, DISABLED_GenerateValidFreespacePullOutPath) { const auto start_pose = geometry_msgs::build() From cde1c78dd8d971514650793448f177a688667321 Mon Sep 17 00:00:00 2001 From: Mamoru Sobue Date: Thu, 16 Jan 2025 18:30:31 +0900 Subject: [PATCH 46/61] feat(planning_factor)!: remove velocity_factor, steering_factor and introduce planning_factor (#9927) Signed-off-by: satoshi-ota Signed-off-by: Mamoru Sobue Co-authored-by: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Co-authored-by: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> Co-authored-by: satoshi-ota --- .../planner_interface.hpp | 11 +- .../obstacle_cruise_planner/type_alias.hpp | 5 - .../obstacle_cruise_planner/utils.hpp | 3 - .../package.xml | 1 - .../src/node.cpp | 1 + .../pid_based_planner/pid_based_planner.cpp | 7 +- .../src/planner_interface.cpp | 18 +- .../src/utils.cpp | 21 -- .../package.xml | 1 - .../src/debug_marker.cpp | 33 +-- .../src/debug_marker.hpp | 14 +- .../src/interface.cpp | 4 +- .../src/interface.hpp | 3 +- .../src/manager.cpp | 2 +- .../manager.hpp | 2 +- .../scene.hpp | 3 +- .../src/scene.cpp | 5 +- .../src/manager.cpp | 4 +- .../goal_planner_module.hpp | 5 +- .../src/goal_planner_module.cpp | 26 +-- .../src/manager.cpp | 2 +- .../interface.hpp | 1 + .../src/interface.cpp | 48 ++-- .../src/manager.cpp | 2 +- .../behavior_path_planner_node.hpp | 7 +- .../src/behavior_path_planner_node.cpp | 39 ++-- .../src/planner_manager.cpp | 3 +- .../interface/scene_module_interface.hpp | 44 ++-- .../scene_module_manager_interface.hpp | 50 +--- .../scene_module_manager_interface.cpp | 9 +- .../manager.hpp | 2 +- .../sampling_planner_module.hpp | 3 +- .../src/sampling_planner_module.cpp | 5 +- .../manager.hpp | 2 +- .../behavior_path_side_shift_module/scene.hpp | 3 +- .../src/scene.cpp | 5 +- .../manager.hpp | 2 +- .../start_planner_module.hpp | 11 +- .../src/start_planner_module.cpp | 39 ++-- .../manager.hpp | 2 +- .../scene.hpp | 15 +- .../src/scene.cpp | 20 +- .../scene.hpp | 4 +- .../src/decisions.cpp | 14 +- .../src/manager.cpp | 2 +- .../src/scene.cpp | 7 +- .../src/manager.cpp | 4 +- .../src/scene_crosswalk.cpp | 23 +- .../src/scene_crosswalk.hpp | 4 +- .../src/manager.cpp | 3 +- .../src/scene.cpp | 6 +- .../src/scene.hpp | 4 +- .../src/manager.cpp | 9 +- .../src/scene_intersection.cpp | 167 ++++++++----- .../src/scene_intersection.hpp | 4 +- .../src/scene_merge_from_private_road.cpp | 13 +- .../src/scene_merge_from_private_road.hpp | 4 +- .../src/manager.cpp | 3 +- .../src/scene.cpp | 8 +- .../src/scene.hpp | 4 +- .../src/manager.cpp | 2 +- .../src/scene_no_stopping_area.cpp | 7 +- .../src/scene_no_stopping_area.hpp | 4 +- .../src/manager.cpp | 4 +- .../src/scene_occlusion_spot.cpp | 7 +- .../src/scene_occlusion_spot.hpp | 4 +- .../scene_module_interface.hpp | 22 +- .../src/scene_module_interface.cpp | 7 +- .../scene_module_interface_with_rtc.hpp | 4 +- .../src/scene_module_interface_with_rtc.cpp | 6 +- .../src/manager.cpp | 3 +- .../src/scene.cpp | 22 +- .../src/scene.hpp | 4 +- .../src/manager.cpp | 2 +- .../src/scene.cpp | 7 +- .../src/scene.hpp | 5 +- .../src/manager.cpp | 2 +- .../src/scene.cpp | 7 +- .../src/scene.hpp | 5 +- .../test/test_scene.cpp | 5 +- .../src/manager.cpp | 5 +- .../src/scene.cpp | 7 +- .../src/scene.hpp | 6 +- .../src/manager.cpp | 3 +- .../src/scene.cpp | 6 +- .../src/scene.hpp | 4 +- .../src/manager.cpp | 3 +- .../src/scene.cpp | 7 +- .../src/scene.hpp | 5 +- .../src/manager.cpp | 3 +- .../src/scene_walkway.cpp | 16 +- .../src/scene_walkway.hpp | 4 +- .../src/dynamic_obstacle_stop_module.cpp | 16 +- .../src/dynamic_obstacle_stop_module.hpp | 1 + .../src/obstacle_velocity_limiter_module.cpp | 1 - .../src/out_of_lane_module.cpp | 16 +- .../src/out_of_lane_module.hpp | 1 + .../plugin_module_interface.hpp | 10 +- .../velocity_planning_result.hpp | 2 - .../README.md | 8 +- .../src/node.cpp | 10 - .../src/node.hpp | 2 - .../src/planner_manager.cpp | 2 + system/autoware_default_adapi/package.xml | 1 + .../autoware_default_adapi/src/planning.cpp | 221 ++++++++++++++---- .../autoware_default_adapi/src/planning.hpp | 20 +- 106 files changed, 731 insertions(+), 544 deletions(-) diff --git a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp index ef6ae1662dcee..823771e173c48 100644 --- a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp +++ b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp @@ -15,6 +15,7 @@ #ifndef AUTOWARE__OBSTACLE_CRUISE_PLANNER__PLANNER_INTERFACE_HPP_ #define AUTOWARE__OBSTACLE_CRUISE_PLANNER__PLANNER_INTERFACE_HPP_ +#include "autoware/motion_utils/factor/planning_factor_interface.hpp" #include "autoware/motion_utils/trajectory/trajectory.hpp" #include "autoware/obstacle_cruise_planner/common_structs.hpp" #include "autoware/obstacle_cruise_planner/stop_planning_debug_info.hpp" @@ -47,15 +48,15 @@ class PlannerInterface rclcpp::Node & node, const LongitudinalInfo & longitudinal_info, const autoware::vehicle_info_utils::VehicleInfo & vehicle_info, const EgoNearestParam & ego_nearest_param, const std::shared_ptr debug_data_ptr) - : longitudinal_info_(longitudinal_info), + : planning_factor_interface_{std::make_unique( + &node, "obstacle_cruise_planner")}, + longitudinal_info_(longitudinal_info), vehicle_info_(vehicle_info), ego_nearest_param_(ego_nearest_param), debug_data_ptr_(debug_data_ptr), slow_down_param_(SlowDownParam(node)), stop_param_(StopParam(node, longitudinal_info)) { - velocity_factors_pub_ = - node.create_publisher("/planning/velocity_factors/obstacle_cruise", 1); stop_speed_exceeded_pub_ = node.create_publisher("~/output/stop_speed_exceeded", 1); metrics_pub_ = node.create_publisher("~/metrics", 10); @@ -101,6 +102,7 @@ class PlannerInterface const std::optional & stop_pose = std::nullopt, const std::optional & stop_obstacle = std::nullopt); void publishMetrics(const rclcpp::Time & current_time); + void publishPlanningFactors() { planning_factor_interface_->publish(); } void clearMetrics(); void onParam(const std::vector & parameters) @@ -128,6 +130,8 @@ class PlannerInterface double getSafeDistanceMargin() const { return longitudinal_info_.safe_distance_margin; } protected: + std::unique_ptr planning_factor_interface_; + // Parameters bool enable_debug_info_{false}; bool enable_calculation_time_info_{false}; @@ -145,7 +149,6 @@ class PlannerInterface stop_watch_; // Publishers - rclcpp::Publisher::SharedPtr velocity_factors_pub_; rclcpp::Publisher::SharedPtr stop_speed_exceeded_pub_; rclcpp::Publisher::SharedPtr metrics_pub_; diff --git a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/type_alias.hpp b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/type_alias.hpp index 04badd2a956ef..31344903b6809 100644 --- a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/type_alias.hpp +++ b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/type_alias.hpp @@ -17,8 +17,6 @@ #include "autoware_vehicle_info_utils/vehicle_info_utils.hpp" -#include "autoware_adapi_v1_msgs/msg/planning_behavior.hpp" -#include "autoware_adapi_v1_msgs/msg/velocity_factor_array.hpp" #include "autoware_perception_msgs/msg/predicted_object.hpp" #include "autoware_perception_msgs/msg/predicted_objects.hpp" #include "autoware_planning_msgs/msg/trajectory.hpp" @@ -39,9 +37,6 @@ #include using autoware::vehicle_info_utils::VehicleInfo; -using autoware_adapi_v1_msgs::msg::PlanningBehavior; -using autoware_adapi_v1_msgs::msg::VelocityFactor; -using autoware_adapi_v1_msgs::msg::VelocityFactorArray; using autoware_perception_msgs::msg::ObjectClassification; using autoware_perception_msgs::msg::PredictedObject; using autoware_perception_msgs::msg::PredictedObjects; diff --git a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/utils.hpp b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/utils.hpp index d929647d9bcd0..ebabd96a54608 100644 --- a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/utils.hpp +++ b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/utils.hpp @@ -94,9 +94,6 @@ size_t getIndexWithLongitudinalOffset( return 0; } -VelocityFactorArray makeVelocityFactorArray( - const rclcpp::Time & time, const std::string & behavior = PlanningBehavior::ROUTE_OBSTACLE, - const std::optional pose = std::nullopt); } // namespace obstacle_cruise_utils #endif // AUTOWARE__OBSTACLE_CRUISE_PLANNER__UTILS_HPP_ diff --git a/planning/autoware_obstacle_cruise_planner/package.xml b/planning/autoware_obstacle_cruise_planner/package.xml index 8583d0639e5ce..7c6d0b286c9b0 100644 --- a/planning/autoware_obstacle_cruise_planner/package.xml +++ b/planning/autoware_obstacle_cruise_planner/package.xml @@ -18,7 +18,6 @@ ament_cmake_auto autoware_cmake - autoware_adapi_v1_msgs autoware_interpolation autoware_lanelet2_extension autoware_motion_utils diff --git a/planning/autoware_obstacle_cruise_planner/src/node.cpp b/planning/autoware_obstacle_cruise_planner/src/node.cpp index 6931ff58e8457..4242f0d559946 100644 --- a/planning/autoware_obstacle_cruise_planner/src/node.cpp +++ b/planning/autoware_obstacle_cruise_planner/src/node.cpp @@ -726,6 +726,7 @@ void ObstacleCruisePlannerNode::onTrajectory(const Trajectory::ConstSharedPtr ms // 8. Publish debug data published_time_publisher_->publish_if_subscribed(trajectory_pub_, output_traj.header.stamp); planner_ptr_->publishMetrics(now()); + planner_ptr_->publishPlanningFactors(); publishDebugMarker(); publishDebugInfo(); objects_of_interest_marker_interface_.publishMarkerArray(); diff --git a/planning/autoware_obstacle_cruise_planner/src/pid_based_planner/pid_based_planner.cpp b/planning/autoware_obstacle_cruise_planner/src/pid_based_planner/pid_based_planner.cpp index 544597f05ff75..20b564addf149 100644 --- a/planning/autoware_obstacle_cruise_planner/src/pid_based_planner/pid_based_planner.cpp +++ b/planning/autoware_obstacle_cruise_planner/src/pid_based_planner/pid_based_planner.cpp @@ -335,9 +335,10 @@ std::vector PIDBasedPlanner::planCruise( debug_data_ptr_->obstacles_to_cruise.push_back(cruise_obstacle_info->obstacle); debug_data_ptr_->cruise_metrics = makeMetrics("PIDBasedPlanner", "cruise", planner_data); - velocity_factors_pub_->publish(obstacle_cruise_utils::makeVelocityFactorArray( - planner_data.current_time, PlanningBehavior::ADAPTIVE_CRUISE, - stop_traj_points.at(wall_idx).pose)); + planning_factor_interface_->add( + stop_traj_points, planner_data.ego_pose, stop_traj_points.at(wall_idx).pose, + tier4_planning_msgs::msg::PlanningFactor::NONE, + tier4_planning_msgs::msg::SafetyFactorArray{}); } // do cruise planning diff --git a/planning/autoware_obstacle_cruise_planner/src/planner_interface.cpp b/planning/autoware_obstacle_cruise_planner/src/planner_interface.cpp index b08bb10ef69cf..b32d7f3a1bcbb 100644 --- a/planning/autoware_obstacle_cruise_planner/src/planner_interface.cpp +++ b/planning/autoware_obstacle_cruise_planner/src/planner_interface.cpp @@ -182,8 +182,6 @@ std::vector PlannerInterface::generateStopTrajectory( : std::abs(vehicle_info_.min_longitudinal_offset_m); if (stop_obstacles.empty()) { - velocity_factors_pub_->publish( - obstacle_cruise_utils::makeVelocityFactorArray(planner_data.current_time)); // delete marker const auto markers = autoware::motion_utils::createDeletedStopVirtualWallMarker(planner_data.current_time, 0); @@ -336,8 +334,10 @@ std::vector PlannerInterface::generateStopTrajectory( // Publish Stop Reason const auto stop_pose = output_traj_points.at(*zero_vel_idx).pose; - velocity_factors_pub_->publish(obstacle_cruise_utils::makeVelocityFactorArray( - planner_data.current_time, PlanningBehavior::ROUTE_OBSTACLE, stop_pose)); + planning_factor_interface_->add( + output_traj_points, planner_data.ego_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}); // Store stop reason debug data debug_data_ptr_->stop_metrics = makeMetrics("PlannerInterface", "stop", planner_data, stop_pose, *determined_stop_obstacle); @@ -590,10 +590,14 @@ std::vector PlannerInterface::generateSlowDownTrajectory( const auto markers = autoware::motion_utils::createSlowDownVirtualWallMarker( slow_down_traj_points.at(slow_down_wall_idx).pose, "obstacle slow down", planner_data.current_time, i, abs_ego_offset, "", planner_data.is_driving_forward); - velocity_factors_pub_->publish(obstacle_cruise_utils::makeVelocityFactorArray( - planner_data.current_time, PlanningBehavior::ROUTE_OBSTACLE, - slow_down_traj_points.at(slow_down_wall_idx).pose)); autoware::universe_utils::appendMarkerArray(markers, &debug_data_ptr_->slow_down_wall_marker); + planning_factor_interface_->add( + slow_down_traj_points, planner_data.ego_pose, + slow_down_traj_points.at(*slow_down_start_idx).pose, + slow_down_traj_points.at(*slow_down_end_idx).pose, + tier4_planning_msgs::msg::PlanningFactor::SLOW_DOWN, + tier4_planning_msgs::msg::SafetyFactorArray{}, planner_data.is_driving_forward, + stable_slow_down_vel); } // add debug virtual wall diff --git a/planning/autoware_obstacle_cruise_planner/src/utils.cpp b/planning/autoware_obstacle_cruise_planner/src/utils.cpp index 82f4e6978181f..b27def0bfcbe5 100644 --- a/planning/autoware_obstacle_cruise_planner/src/utils.cpp +++ b/planning/autoware_obstacle_cruise_planner/src/utils.cpp @@ -118,25 +118,4 @@ std::vector getClosestStopObstacles(const std::vector pose) -{ - VelocityFactorArray velocity_factor_array; - velocity_factor_array.header.frame_id = "map"; - velocity_factor_array.header.stamp = time; - - if (pose) { - using distance_type = VelocityFactor::_distance_type; - VelocityFactor velocity_factor; - velocity_factor.behavior = behavior; - velocity_factor.pose = pose.value(); - velocity_factor.distance = std::numeric_limits::quiet_NaN(); - velocity_factor.status = VelocityFactor::UNKNOWN; - velocity_factor.detail = std::string(); - velocity_factor_array.factors.push_back(velocity_factor); - } - return velocity_factor_array; -} - } // namespace obstacle_cruise_utils diff --git a/planning/autoware_surround_obstacle_checker/package.xml b/planning/autoware_surround_obstacle_checker/package.xml index 4a6f946b8eb90..8bbc0b6bf4e02 100644 --- a/planning/autoware_surround_obstacle_checker/package.xml +++ b/planning/autoware_surround_obstacle_checker/package.xml @@ -14,7 +14,6 @@ autoware_cmake eigen3_cmake_module - autoware_adapi_v1_msgs autoware_motion_utils autoware_perception_msgs autoware_planning_msgs diff --git a/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp b/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp index bbd1cac04ed89..2acf6ba1c92f5 100644 --- a/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp +++ b/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp @@ -67,7 +67,9 @@ SurroundObstacleCheckerDebugNode::SurroundObstacleCheckerDebugNode( const double & surround_check_back_distance, const double & surround_check_hysteresis_distance, const geometry_msgs::msg::Pose & self_pose, const rclcpp::Clock::SharedPtr clock, rclcpp::Node & node) -: vehicle_info_(vehicle_info), +: planning_factor_interface_{std::make_unique( + &node, "surround_obstacle_checker")}, + vehicle_info_(vehicle_info), object_label_(object_label), surround_check_front_distance_(surround_check_front_distance), surround_check_side_distance_(surround_check_side_distance), @@ -77,8 +79,6 @@ SurroundObstacleCheckerDebugNode::SurroundObstacleCheckerDebugNode( clock_(clock) { debug_viz_pub_ = node.create_publisher("~/debug/marker", 1); - velocity_factor_pub_ = - node.create_publisher("/planning/velocity_factors/surround_obstacle", 1); vehicle_footprint_pub_ = node.create_publisher("~/debug/footprint", 1); vehicle_footprint_offset_pub_ = node.create_publisher("~/debug/footprint_offset", 1); @@ -143,8 +143,12 @@ void SurroundObstacleCheckerDebugNode::publish() debug_viz_pub_->publish(visualization_msg); /* publish stop reason for autoware api */ - const auto velocity_factor_msg = makeVelocityFactorArray(); - velocity_factor_pub_->publish(velocity_factor_msg); + if (stop_pose_ptr_ != nullptr) { + planning_factor_interface_->add( + 0.0, *stop_pose_ptr_, tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}); + } + planning_factor_interface_->publish(); /* reset variables */ stop_pose_ptr_ = nullptr; @@ -170,25 +174,6 @@ MarkerArray SurroundObstacleCheckerDebugNode::makeVisualizationMarker() return msg; } -VelocityFactorArray SurroundObstacleCheckerDebugNode::makeVelocityFactorArray() -{ - VelocityFactorArray velocity_factor_array; - velocity_factor_array.header.frame_id = "map"; - velocity_factor_array.header.stamp = clock_->now(); - - if (stop_pose_ptr_) { - using distance_type = VelocityFactor::_distance_type; - VelocityFactor velocity_factor; - velocity_factor.behavior = PlanningBehavior::SURROUNDING_OBSTACLE; - velocity_factor.pose = *stop_pose_ptr_; - velocity_factor.distance = std::numeric_limits::quiet_NaN(); - velocity_factor.status = VelocityFactor::UNKNOWN; - velocity_factor.detail = std::string(); - velocity_factor_array.factors.push_back(velocity_factor); - } - return velocity_factor_array; -} - PolygonStamped SurroundObstacleCheckerDebugNode::boostPolygonToPolygonStamped( const Polygon2d & boost_polygon, const double & z) { diff --git a/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp b/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp index b2c350c1b4698..c49e277f2dc6c 100644 --- a/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp +++ b/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp @@ -15,13 +15,13 @@ #ifndef DEBUG_MARKER_HPP_ #define DEBUG_MARKER_HPP_ +#include #include #include -#include -#include #include #include +#include #include #include @@ -34,10 +34,10 @@ namespace autoware::surround_obstacle_checker { using autoware::vehicle_info_utils::VehicleInfo; -using autoware_adapi_v1_msgs::msg::PlanningBehavior; -using autoware_adapi_v1_msgs::msg::VelocityFactor; -using autoware_adapi_v1_msgs::msg::VelocityFactorArray; using geometry_msgs::msg::PolygonStamped; +using tier4_planning_msgs::msg::ControlPoint; +using tier4_planning_msgs::msg::PlanningFactor; +using tier4_planning_msgs::msg::PlanningFactorArray; using visualization_msgs::msg::Marker; using visualization_msgs::msg::MarkerArray; @@ -65,12 +65,13 @@ class SurroundObstacleCheckerDebugNode private: rclcpp::Publisher::SharedPtr debug_viz_pub_; - rclcpp::Publisher::SharedPtr velocity_factor_pub_; rclcpp::Publisher::SharedPtr vehicle_footprint_pub_; rclcpp::Publisher::SharedPtr vehicle_footprint_offset_pub_; rclcpp::Publisher::SharedPtr vehicle_footprint_recover_offset_pub_; + std::unique_ptr planning_factor_interface_; + autoware::vehicle_info_utils::VehicleInfo vehicle_info_; std::string object_label_; double surround_check_front_distance_; @@ -80,7 +81,6 @@ class SurroundObstacleCheckerDebugNode geometry_msgs::msg::Pose self_pose_; MarkerArray makeVisualizationMarker(); - VelocityFactorArray makeVelocityFactorArray(); PolygonStamped boostPolygonToPolygonStamped(const Polygon2d & boost_polygon, const double & z); diff --git a/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.cpp b/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.cpp index 3080ba1045b41..37bee1a178f90 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.cpp @@ -32,13 +32,15 @@ AvoidanceByLaneChangeInterface::AvoidanceByLaneChangeInterface( const std::shared_ptr & avoidance_by_lane_change_parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map) + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr & planning_factor_interface) : LaneChangeInterface{ name, node, parameters, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, + planning_factor_interface, std::make_unique(parameters, avoidance_by_lane_change_parameters)} { } diff --git a/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.hpp b/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.hpp index c7fbba34b1adb..6e524f3c91341 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/interface.hpp @@ -40,7 +40,8 @@ class AvoidanceByLaneChangeInterface : public LaneChangeInterface const std::shared_ptr & avoidance_by_lane_change_parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map); + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr & planning_factor_interface); bool isExecutionRequested() const override; diff --git a/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/manager.cpp index c54774a575332..2bf8a60676d72 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_avoidance_by_lane_change_module/src/manager.cpp @@ -190,7 +190,7 @@ SMIPtr AvoidanceByLaneChangeModuleManager::createNewSceneModuleInstance() { return std::make_unique( name_, *node_, parameters_, avoidance_parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_); + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_); } } // namespace autoware::behavior_path_planner diff --git a/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/manager.hpp b/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/manager.hpp index f09196b2cc8e1..ea8f09c4f9336 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/manager.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/manager.hpp @@ -42,7 +42,7 @@ class DynamicObstacleAvoidanceModuleManager : public SceneModuleManagerInterface { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_); + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_); } void updateModuleParams(const std::vector & parameters) override; diff --git a/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/scene.hpp b/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/scene.hpp index 44b56f4ea0990..8987e7c0446ee 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/scene.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/include/autoware/behavior_path_dynamic_obstacle_avoidance_module/scene.hpp @@ -351,7 +351,8 @@ class DynamicObstacleAvoidanceModule : public SceneModuleInterface std::shared_ptr parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map); + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface); void updateModuleParams(const std::any & parameters) override { diff --git a/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/src/scene.cpp b/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/src/scene.cpp index dc7efebe88fba..145e0df2675b4 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/src/scene.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_dynamic_obstacle_avoidance_module/src/scene.cpp @@ -331,8 +331,9 @@ DynamicObstacleAvoidanceModule::DynamicObstacleAvoidanceModule( std::shared_ptr parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map) -: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, planning_factor_interface}, // NOLINT parameters_{std::move(parameters)}, target_objects_manager_{TargetObjectsManager( parameters_->successive_num_to_entry_dynamic_avoidance_condition, diff --git a/planning/behavior_path_planner/autoware_behavior_path_external_request_lane_change_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_external_request_lane_change_module/src/manager.cpp index 45c997f364633..0b438d1a1758e 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_external_request_lane_change_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_external_request_lane_change_module/src/manager.cpp @@ -28,7 +28,7 @@ ExternalRequestLaneChangeRightModuleManager::createNewSceneModuleInstance() { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_, + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_, std::make_unique(parameters_, direction_)); } @@ -37,7 +37,7 @@ ExternalRequestLaneChangeLeftModuleManager::createNewSceneModuleInstance() { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_, + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_, std::make_unique(parameters_, direction_)); } diff --git a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/include/autoware/behavior_path_goal_planner_module/goal_planner_module.hpp b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/include/autoware/behavior_path_goal_planner_module/goal_planner_module.hpp index 41524b1b8193c..84367fdd91b80 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/include/autoware/behavior_path_goal_planner_module/goal_planner_module.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/include/autoware/behavior_path_goal_planner_module/goal_planner_module.hpp @@ -240,7 +240,8 @@ class GoalPlannerModule : public SceneModuleInterface const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map); + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface); ~GoalPlannerModule() { @@ -455,7 +456,7 @@ class GoalPlannerModule : public SceneModuleInterface // steering factor void updateSteeringFactor( const PullOverContextData & context_data, const std::array & pose, - const std::array distance, const uint16_t type); + const std::array distance); // rtc std::pair calcDistanceToPathChange( diff --git a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/goal_planner_module.cpp b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/goal_planner_module.cpp index 0a6185127fcf0..c7e32a47a59f9 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/goal_planner_module.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/goal_planner_module.cpp @@ -66,8 +66,9 @@ GoalPlannerModule::GoalPlannerModule( const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map) -: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, planning_factor_interface}, // NOLINT parameters_{parameters}, vehicle_info_{autoware::vehicle_info_utils::VehicleInfoUtils(node).getVehicleInfo()}, is_lane_parking_cb_running_{false}, @@ -120,9 +121,6 @@ GoalPlannerModule::GoalPlannerModule( initializeSafetyCheckParameters(); } - steering_factor_interface_.init(PlanningBehavior::GOAL_PLANNER); - velocity_factor_interface_.init(PlanningBehavior::GOAL_PLANNER); - /** * NOTE: Add `universe_utils::ScopedTimeTrack st(__func__, *time_keeper_);` to functions called * from the main thread only. @@ -1344,19 +1342,20 @@ void GoalPlannerModule::setTurnSignalInfo( void GoalPlannerModule::updateSteeringFactor( const PullOverContextData & context_data, const std::array & pose, - const std::array distance, const uint16_t type) + const std::array distance) { - const uint16_t steering_factor_direction = std::invoke([&]() { + const uint16_t planning_factor_direction = std::invoke([&]() { const auto turn_signal = calcTurnSignalInfo(context_data); if (turn_signal.turn_signal.command == TurnIndicatorsCommand::ENABLE_LEFT) { - return SteeringFactor::LEFT; + return PlanningFactor::SHIFT_LEFT; } else if (turn_signal.turn_signal.command == TurnIndicatorsCommand::ENABLE_RIGHT) { - return SteeringFactor::RIGHT; + return PlanningFactor::SHIFT_RIGHT; } - return SteeringFactor::STRAIGHT; + return PlanningFactor::NONE; }); - steering_factor_interface_.set(pose, distance, steering_factor_direction, type, ""); + planning_factor_interface_->add( + distance[0], distance[1], pose[0], pose[1], planning_factor_direction, SafetyFactorArray{}); } void GoalPlannerModule::decideVelocity(PullOverPath & pull_over_path) @@ -1568,10 +1567,9 @@ void GoalPlannerModule::postProcess() updateSteeringFactor( context_data, {pull_over_path.start_pose(), pull_over_path.modified_goal_pose()}, - {distance_to_path_change.first, distance_to_path_change.second}, - has_decided_path ? SteeringFactor::TURNING : SteeringFactor::APPROACHING); + {distance_to_path_change.first, distance_to_path_change.second}); - setVelocityFactor(pull_over_path.full_path()); + set_longitudinal_planning_factor(pull_over_path.full_path()); } BehaviorModuleOutput GoalPlannerModule::planWaitingApproval() diff --git a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/manager.cpp index 6bbc34a495080..a99252c923328 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/manager.cpp @@ -31,7 +31,7 @@ std::unique_ptr GoalPlannerModuleManager::createNewSceneMo { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_); + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_); } GoalPlannerParameters GoalPlannerModuleManager::initGoalPlannerParameters( diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/interface.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/interface.hpp index 4b97fb0d069a0..82b042d1135d2 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/interface.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/interface.hpp @@ -53,6 +53,7 @@ class LaneChangeInterface : public SceneModuleInterface const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr & planning_factor_interface, std::unique_ptr && module_type); LaneChangeInterface(const LaneChangeInterface &) = delete; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/interface.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/interface.cpp index ebcd4eb4809fc..4519b20d4644d 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/interface.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/interface.cpp @@ -40,15 +40,14 @@ LaneChangeInterface::LaneChangeInterface( const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr & planning_factor_interface, std::unique_ptr && module_type) -: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT +: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, planning_factor_interface}, // NOLINT parameters_{std::move(parameters)}, module_type_{std::move(module_type)} { module_type_->setTimeKeeper(getTimeKeeper()); logger_ = utils::lane_change::getLogger(module_type_->getModuleTypeStr()); - steering_factor_interface_.init(PlanningBehavior::LANE_CHANGE); - velocity_factor_interface_.init(PlanningBehavior::LANE_CHANGE); } void LaneChangeInterface::processOnExit() @@ -145,7 +144,7 @@ BehaviorModuleOutput LaneChangeInterface::plan() } } - setVelocityFactor(output.path); + set_longitudinal_planning_factor(output.path); return output; } @@ -179,7 +178,7 @@ BehaviorModuleOutput LaneChangeInterface::planWaitingApproval() isExecutionReady(), State::WAITING_FOR_EXECUTION); is_abort_path_approved_ = false; - setVelocityFactor(out.path); + set_longitudinal_planning_factor(out.path); return out; } @@ -384,15 +383,6 @@ MarkerArray LaneChangeInterface::getModuleVirtualWall() void LaneChangeInterface::updateSteeringFactorPtr(const BehaviorModuleOutput & output) { universe_utils::ScopedTimeTrack st(__func__, *getTimeKeeper()); - const auto steering_factor_direction = std::invoke([&]() { - if (module_type_->getDirection() == Direction::LEFT) { - return SteeringFactor::LEFT; - } - if (module_type_->getDirection() == Direction::RIGHT) { - return SteeringFactor::RIGHT; - } - return SteeringFactor::UNKNOWN; - }); const auto current_position = module_type_->getEgoPosition(); const auto status = module_type_->getLaneChangeStatus(); @@ -401,24 +391,34 @@ void LaneChangeInterface::updateSteeringFactorPtr(const BehaviorModuleOutput & o const auto finish_distance = autoware::motion_utils::calcSignedArcLength( output.path.points, current_position, status.lane_change_path.info.shift_line.end.position); - steering_factor_interface_.set( - {status.lane_change_path.info.shift_line.start, status.lane_change_path.info.shift_line.end}, - {start_distance, finish_distance}, steering_factor_direction, SteeringFactor::TURNING, ""); + const auto planning_factor_direction = std::invoke([&]() { + if (module_type_->getDirection() == Direction::LEFT) { + return PlanningFactor::SHIFT_LEFT; + } + if (module_type_->getDirection() == Direction::RIGHT) { + return PlanningFactor::SHIFT_RIGHT; + } + return PlanningFactor::UNKNOWN; + }); + + planning_factor_interface_->add( + start_distance, finish_distance, status.lane_change_path.info.shift_line.start, + status.lane_change_path.info.shift_line.end, planning_factor_direction, SafetyFactorArray{}); } void LaneChangeInterface::updateSteeringFactorPtr( const CandidateOutput & output, const LaneChangePath & selected_path) const { - const uint16_t steering_factor_direction = std::invoke([&output]() { + const uint16_t planning_factor_direction = std::invoke([&output]() { if (output.lateral_shift > 0.0) { - return SteeringFactor::LEFT; + return PlanningFactor::SHIFT_LEFT; } - return SteeringFactor::RIGHT; + return PlanningFactor::SHIFT_RIGHT; }); - steering_factor_interface_.set( - {selected_path.info.shift_line.start, selected_path.info.shift_line.end}, - {output.start_distance_to_path_change, output.finish_distance_to_path_change}, - steering_factor_direction, SteeringFactor::APPROACHING, ""); + planning_factor_interface_->add( + output.start_distance_to_path_change, output.finish_distance_to_path_change, + selected_path.info.shift_line.start, selected_path.info.shift_line.end, + planning_factor_direction, SafetyFactorArray{}); } } // namespace autoware::behavior_path_planner diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp index f26cf79e8b120..450497fb2ca29 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp @@ -302,7 +302,7 @@ std::unique_ptr LaneChangeModuleManager::createNewSceneMod { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_, + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_, std::make_unique(parameters_, LaneChangeModuleType::NORMAL, direction_)); } diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp b/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp index ebe7c47e6fab2..7f7ecd7326b08 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp @@ -20,7 +20,7 @@ #include "autoware/universe_utils/ros/logger_level_configure.hpp" #include "planner_manager.hpp" -#include +#include #include #include @@ -51,7 +51,7 @@ namespace autoware::behavior_path_planner { -using autoware::motion_utils::SteeringFactorInterface; +using autoware::motion_utils::PlanningFactorInterface; using autoware_adapi_v1_msgs::msg::OperationModeState; using autoware_map_msgs::msg::LaneletMapBin; using autoware_perception_msgs::msg::PredictedObject; @@ -121,7 +121,6 @@ class BehaviorPathPlannerNode : public rclcpp::Node rclcpp::Publisher::SharedPtr bound_publisher_; rclcpp::Publisher::SharedPtr modified_goal_publisher_; rclcpp::Publisher::SharedPtr reroute_availability_publisher_; - rclcpp::Publisher::SharedPtr pub_steering_factors_; rclcpp::TimerBase::SharedPtr timer_; std::map::SharedPtr> path_candidate_publishers_; @@ -136,7 +135,7 @@ class BehaviorPathPlannerNode : public rclcpp::Node std::shared_ptr planner_manager_; - SteeringFactorInterface steering_factor_interface_; + std::unique_ptr planning_factor_interface_; std::mutex mutex_pd_; // mutex for planner_data_ std::mutex mutex_manager_; // mutex for bt_manager_ or planner_manager_ diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner/src/behavior_path_planner_node.cpp b/planning/behavior_path_planner/autoware_behavior_path_planner/src/behavior_path_planner_node.cpp index 7758ab530e88c..568d432e1faa3 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner/src/behavior_path_planner_node.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner/src/behavior_path_planner_node.cpp @@ -32,7 +32,9 @@ using autoware::vehicle_info_utils::VehicleInfoUtils; using tier4_planning_msgs::msg::PathChangeModuleId; BehaviorPathPlannerNode::BehaviorPathPlannerNode(const rclcpp::NodeOptions & node_options) -: Node("behavior_path_planner", node_options) +: Node("behavior_path_planner", node_options), + planning_factor_interface_{ + std::make_unique(this, "behavior_path_planner")} { using std::placeholders::_1; using std::chrono_literals::operator""ms; @@ -51,8 +53,6 @@ BehaviorPathPlannerNode::BehaviorPathPlannerNode(const rclcpp::NodeOptions & nod const auto durable_qos = rclcpp::QoS(1).transient_local(); modified_goal_publisher_ = create_publisher("~/output/modified_goal", durable_qos); - pub_steering_factors_ = - create_publisher("/planning/steering_factor/intersection", 1); reroute_availability_publisher_ = create_publisher("~/output/is_reroute_available", 1); debug_avoidance_msg_array_publisher_ = @@ -115,8 +115,6 @@ BehaviorPathPlannerNode::BehaviorPathPlannerNode(const rclcpp::NodeOptions & nod turn_signal_search_time, turn_signal_intersection_angle_threshold_deg); } - steering_factor_interface_.init(PlanningBehavior::INTERSECTION); - // Start timer { const auto planning_hz = declare_parameter("planning_hz"); @@ -463,33 +461,22 @@ void BehaviorPathPlannerNode::publish_steering_factor( const auto [intersection_flag, approaching_intersection_flag] = planner_data->turn_signal_decider.getIntersectionTurnSignalFlag(); if (intersection_flag || approaching_intersection_flag) { - const uint16_t steering_factor_direction = std::invoke([&turn_signal]() { - if (turn_signal.command == TurnIndicatorsCommand::ENABLE_LEFT) { - return SteeringFactor::LEFT; - } - return SteeringFactor::RIGHT; - }); - const auto [intersection_pose, intersection_distance] = planner_data->turn_signal_decider.getIntersectionPoseAndDistance(); - steering_factor_interface_.set( - {intersection_pose, intersection_pose}, {intersection_distance, intersection_distance}, - steering_factor_direction, SteeringFactor::TURNING, ""); - } else { - steering_factor_interface_.reset(); - } - - autoware_adapi_v1_msgs::msg::SteeringFactorArray steering_factor_array; - steering_factor_array.header.frame_id = "map"; - steering_factor_array.header.stamp = this->now(); + const uint16_t planning_factor_direction = std::invoke([&turn_signal]() { + if (turn_signal.command == TurnIndicatorsCommand::ENABLE_LEFT) { + return PlanningFactor::TURN_LEFT; + } + return PlanningFactor::TURN_RIGHT; + }); - const auto steering_factor = steering_factor_interface_.get(); - if (steering_factor.behavior != PlanningBehavior::UNKNOWN) { - steering_factor_array.factors.emplace_back(steering_factor); + planning_factor_interface_->add( + intersection_distance, intersection_distance, intersection_pose, intersection_pose, + planning_factor_direction, SafetyFactorArray{}); } - pub_steering_factors_->publish(steering_factor_array); + planning_factor_interface_->publish(); } void BehaviorPathPlannerNode::publish_reroute_availability() const diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner/src/planner_manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_planner/src/planner_manager.cpp index 041b7ad20a107..322209d46732b 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner/src/planner_manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner/src/planner_manager.cpp @@ -182,8 +182,7 @@ BehaviorModuleOutput PlannerManager::run(const std::shared_ptr & da std::for_each(manager_ptrs_.begin(), manager_ptrs_.end(), [](const auto & m) { m->updateObserver(); m->publishRTCStatus(); - m->publishSteeringFactor(); - m->publishVelocityFactor(); + m->publish_planning_factors(); }); generateCombinedDrivableArea(result_output.valid_output, data); diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp b/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp index 391ac92411220..c96bc601b6403 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp @@ -21,8 +21,7 @@ #include "autoware/behavior_path_planner_common/utils/utils.hpp" #include -#include -#include +#include #include #include #include @@ -36,7 +35,6 @@ #include #include -#include #include #include #include @@ -54,18 +52,16 @@ namespace autoware::behavior_path_planner { -using autoware::motion_utils::SteeringFactorInterface; -using autoware::motion_utils::VelocityFactorInterface; +using autoware::motion_utils::PlanningFactorInterface; using autoware::objects_of_interest_marker_interface::ColorName; using autoware::objects_of_interest_marker_interface::ObjectsOfInterestMarkerInterface; using autoware::rtc_interface::RTCInterface; using autoware::universe_utils::calcOffsetPose; using autoware::universe_utils::generateUUID; -using autoware_adapi_v1_msgs::msg::PlanningBehavior; -using autoware_adapi_v1_msgs::msg::SteeringFactor; -using autoware_adapi_v1_msgs::msg::VelocityFactor; using tier4_planning_msgs::msg::AvoidanceDebugMsgArray; using tier4_planning_msgs::msg::PathWithLaneId; +using tier4_planning_msgs::msg::PlanningFactor; +using tier4_planning_msgs::msg::SafetyFactorArray; using tier4_rtc_msgs::msg::State; using unique_identifier_msgs::msg::UUID; using visualization_msgs::msg::MarkerArray; @@ -86,13 +82,15 @@ class SceneModuleInterface const std::string & name, rclcpp::Node & node, std::unordered_map> rtc_interface_ptr_map, std::unordered_map> - objects_of_interest_marker_interface_ptr_map) + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface) : name_{name}, logger_{node.get_logger().get_child(name)}, clock_{node.get_clock()}, rtc_interface_ptr_map_(std::move(rtc_interface_ptr_map)), objects_of_interest_marker_interface_ptr_map_( std::move(objects_of_interest_marker_interface_ptr_map)), + planning_factor_interface_{planning_factor_interface}, time_keeper_(std::make_shared()) { for (const auto & [module_name, ptr] : rtc_interface_ptr_map_) { @@ -184,8 +182,6 @@ class SceneModuleInterface unlockNewModuleLaunch(); unlockOutputPath(); - reset_factor(); - processOnExit(); } @@ -258,16 +254,6 @@ class SceneModuleInterface ModuleStatus getCurrentStatus() const { return current_state_; } - void reset_factor() - { - steering_factor_interface_.reset(); - velocity_factor_interface_.reset(); - } - - auto get_steering_factor() const -> SteeringFactor { return steering_factor_interface_.get(); } - - auto get_velocity_factor() const -> VelocityFactor { return velocity_factor_interface_.get(); } - std::string name() const { return name_; } PoseWithDetailOpt getStopPose() const @@ -558,11 +544,12 @@ class SceneModuleInterface } } - void setVelocityFactor(const PathWithLaneId & path) + void set_longitudinal_planning_factor(const PathWithLaneId & path) { if (stop_pose_.has_value()) { - velocity_factor_interface_.set( - path.points, getEgoPose(), stop_pose_.value().pose, VelocityFactor::APPROACHING, "stop"); + planning_factor_interface_->add( + path.points, getEgoPose(), stop_pose_.value().pose, PlanningFactor::STOP, + SafetyFactorArray{}); return; } @@ -570,8 +557,9 @@ class SceneModuleInterface return; } - velocity_factor_interface_.set( - path.points, getEgoPose(), slow_pose_.value().pose, VelocityFactor::APPROACHING, "slow down"); + planning_factor_interface_->add( + path.points, getEgoPose(), slow_pose_.value().pose, PlanningFactor::SLOW_DOWN, + SafetyFactorArray{}); } void setDrivableLanes(const std::vector & drivable_lanes); @@ -627,9 +615,7 @@ class SceneModuleInterface std::unordered_map> objects_of_interest_marker_interface_ptr_map_; - mutable SteeringFactorInterface steering_factor_interface_; - - mutable VelocityFactorInterface velocity_factor_interface_; + mutable std::shared_ptr planning_factor_interface_; mutable PoseWithDetailOpt stop_pose_{std::nullopt}; diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_manager_interface.hpp b/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_manager_interface.hpp index 73b133952935b..446829d1d0f9d 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_manager_interface.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_manager_interface.hpp @@ -24,8 +24,6 @@ #include #include -#include -#include #include #include @@ -42,8 +40,6 @@ using autoware::motion_utils::createDeadLineVirtualWallMarker; using autoware::motion_utils::createSlowDownVirtualWallMarker; using autoware::motion_utils::createStopVirtualWallMarker; using autoware::universe_utils::toHexString; -using autoware_adapi_v1_msgs::msg::SteeringFactorArray; -using autoware_adapi_v1_msgs::msg::VelocityFactorArray; using unique_identifier_msgs::msg::UUID; using SceneModulePtr = std::shared_ptr; using SceneModuleObserver = std::weak_ptr; @@ -106,45 +102,7 @@ class SceneModuleManagerInterface } } - void publishSteeringFactor() - { - SteeringFactorArray steering_factor_array; - steering_factor_array.header.frame_id = "map"; - steering_factor_array.header.stamp = node_->now(); - - for (const auto & m : observers_) { - if (m.expired()) { - continue; - } - - const auto steering_factor = m.lock()->get_steering_factor(); - if (steering_factor.behavior != PlanningBehavior::UNKNOWN) { - steering_factor_array.factors.emplace_back(steering_factor); - } - } - - pub_steering_factors_->publish(steering_factor_array); - } - - void publishVelocityFactor() - { - VelocityFactorArray velocity_factor_array; - velocity_factor_array.header.frame_id = "map"; - velocity_factor_array.header.stamp = node_->now(); - - for (const auto & m : observers_) { - if (m.expired()) { - continue; - } - - const auto velocity_factor = m.lock()->get_velocity_factor(); - if (velocity_factor.behavior != PlanningBehavior::UNKNOWN) { - velocity_factor_array.factors.emplace_back(velocity_factor); - } - } - - pub_velocity_factors_->publish(velocity_factor_array); - } + void publish_planning_factors() { planning_factor_interface_->publish(); } void publishVirtualWall() const { @@ -304,10 +262,6 @@ class SceneModuleManagerInterface rclcpp::Publisher::SharedPtr pub_drivable_lanes_; - rclcpp::Publisher::SharedPtr pub_steering_factors_; - - rclcpp::Publisher::SharedPtr pub_velocity_factors_; - rclcpp::Publisher::SharedPtr pub_processing_time_; std::string name_; @@ -318,6 +272,8 @@ class SceneModuleManagerInterface std::unique_ptr idle_module_ptr_; + std::shared_ptr planning_factor_interface_; + std::unordered_map> rtc_interface_ptr_map_; std::unordered_map> diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner_common/src/interface/scene_module_manager_interface.cpp b/planning/behavior_path_planner/autoware_behavior_path_planner_common/src/interface/scene_module_manager_interface.cpp index b91db3a740cfe..11be3b28a7f94 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner_common/src/interface/scene_module_manager_interface.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner_common/src/interface/scene_module_manager_interface.cpp @@ -61,10 +61,11 @@ void SceneModuleManagerInterface::initInterface( pub_drivable_lanes_ = node->create_publisher("~/drivable_lanes/" + name_, 20); pub_processing_time_ = node->create_publisher( "~/processing_time/" + name_, 20); - pub_steering_factors_ = - node->create_publisher("/planning/steering_factor/" + name_, 1); - pub_velocity_factors_ = - node->create_publisher("/planning/velocity_factors/" + name_, 1); + } + + // planning factor + { + planning_factor_interface_ = std::make_shared(node, name_); } // misc diff --git a/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/manager.hpp b/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/manager.hpp index 28c310ae20ec2..f25c073e879da 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/manager.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/manager.hpp @@ -38,7 +38,7 @@ class SamplingPlannerModuleManager : public SceneModuleManagerInterface { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_); + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_); } void updateModuleParams( diff --git a/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/sampling_planner_module.hpp b/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/sampling_planner_module.hpp index c9b75f7fa96de..f84fe45d08ca4 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/sampling_planner_module.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/include/autoware/behavior_path_sampling_planner_module/sampling_planner_module.hpp @@ -86,7 +86,8 @@ class SamplingPlannerModule : public SceneModuleInterface const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map); + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface); bool isExecutionRequested() const override; bool isExecutionReady() const override; diff --git a/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/src/sampling_planner_module.cpp b/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/src/sampling_planner_module.cpp index fac3cc92de1d6..5bb57f17ce813 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/src/sampling_planner_module.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_sampling_planner_module/src/sampling_planner_module.cpp @@ -42,8 +42,9 @@ SamplingPlannerModule::SamplingPlannerModule( const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map) -: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, planning_factor_interface}, // NOLINT vehicle_info_{autoware::vehicle_info_utils::VehicleInfoUtils(node).getVehicleInfo()} { internal_params_ = std::make_shared(); diff --git a/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/manager.hpp b/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/manager.hpp index b495e6619a1c7..2b4a20ddc8cca 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/manager.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/manager.hpp @@ -39,7 +39,7 @@ class SideShiftModuleManager : public SceneModuleManagerInterface { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_); + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_); } void updateModuleParams(const std::vector & parameters) override; diff --git a/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/scene.hpp b/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/scene.hpp index 15d81ff45abcf..c8a5e47287477 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/scene.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/include/autoware/behavior_path_side_shift_module/scene.hpp @@ -45,7 +45,8 @@ class SideShiftModule : public SceneModuleInterface const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map); + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface); bool isExecutionRequested() const override; bool isExecutionReady() const override; diff --git a/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/src/scene.cpp b/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/src/scene.cpp index 22ee7ab77e077..9536c1ba17336 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/src/scene.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_side_shift_module/src/scene.cpp @@ -42,8 +42,9 @@ SideShiftModule::SideShiftModule( const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map) -: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, planning_factor_interface}, // NOLINT parameters_{parameters} { } diff --git a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/manager.hpp b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/manager.hpp index 5d3d224673124..68b1e67e484c3 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/manager.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/manager.hpp @@ -38,7 +38,7 @@ class StartPlannerModuleManager : public SceneModuleManagerInterface { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_); + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_); } void updateModuleParams(const std::vector & parameters) override; diff --git a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/start_planner_module.hpp b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/start_planner_module.hpp index cf9227c2387f8..9b1186cb5fc66 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/start_planner_module.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/include/autoware/behavior_path_start_planner_module/start_planner_module.hpp @@ -86,7 +86,8 @@ class StartPlannerModule : public SceneModuleInterface const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map); + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface); ~StartPlannerModule() override { @@ -198,18 +199,18 @@ class StartPlannerModule : public SceneModuleInterface bool requiresDynamicObjectsCollisionDetection() const; - uint16_t getSteeringFactorDirection( + uint16_t getPlanningFactorDirection( const autoware::behavior_path_planner::BehaviorModuleOutput & output) const { switch (output.turn_signal_info.turn_signal.command) { case TurnIndicatorsCommand::ENABLE_LEFT: - return SteeringFactor::LEFT; + return PlanningFactor::SHIFT_LEFT; case TurnIndicatorsCommand::ENABLE_RIGHT: - return SteeringFactor::RIGHT; + return PlanningFactor::SHIFT_RIGHT; default: - return SteeringFactor::STRAIGHT; + return PlanningFactor::NONE; } }; diff --git a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/start_planner_module.cpp b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/start_planner_module.cpp index 0bac50a37fdbf..ae05bcf4c084e 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/start_planner_module.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/start_planner_module.cpp @@ -62,8 +62,9 @@ StartPlannerModule::StartPlannerModule( const std::shared_ptr & parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map) -: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, planning_factor_interface}, // NOLINT parameters_{parameters}, vehicle_info_{autoware::vehicle_info_utils::VehicleInfoUtils(node).getVehicleInfo()}, is_freespace_planner_cb_running_{false} @@ -89,9 +90,6 @@ StartPlannerModule::StartPlannerModule( std::bind(&StartPlannerModule::onFreespacePlannerTimer, this), freespace_planner_timer_cb_group_); } - - steering_factor_interface_.init(PlanningBehavior::START_PLANNER); - velocity_factor_interface_.init(PlanningBehavior::START_PLANNER); } void StartPlannerModule::onFreespacePlannerTimer() @@ -732,9 +730,9 @@ BehaviorModuleOutput StartPlannerModule::plan() setDrivableAreaInfo(output); - setVelocityFactor(output.path); + set_longitudinal_planning_factor(output.path); - const auto steering_factor_direction = getSteeringFactorDirection(output); + const auto planning_factor_direction = getPlanningFactorDirection(output); if (status_.driving_forward) { const double start_distance = autoware::motion_utils::calcSignedArcLength( @@ -744,9 +742,9 @@ BehaviorModuleOutput StartPlannerModule::plan() path.points, planner_data_->self_odometry->pose.pose.position, status_.pull_out_path.end_pose.position); updateRTCStatus(start_distance, finish_distance); - steering_factor_interface_.set( - {status_.pull_out_path.start_pose, status_.pull_out_path.end_pose}, - {start_distance, finish_distance}, steering_factor_direction, SteeringFactor::TURNING, ""); + planning_factor_interface_->add( + start_distance, finish_distance, status_.pull_out_path.start_pose, + status_.pull_out_path.end_pose, planning_factor_direction, SafetyFactorArray{}); setDebugData(); return output; } @@ -754,9 +752,9 @@ BehaviorModuleOutput StartPlannerModule::plan() path.points, planner_data_->self_odometry->pose.pose.position, status_.pull_out_path.start_pose.position); updateRTCStatus(0.0, distance); - steering_factor_interface_.set( - {status_.pull_out_path.start_pose, status_.pull_out_path.end_pose}, {0.0, distance}, - steering_factor_direction, SteeringFactor::TURNING, ""); + planning_factor_interface_->add( + 0.0, distance, status_.pull_out_path.start_pose, status_.pull_out_path.end_pose, + planning_factor_direction, SafetyFactorArray{}); setDebugData(); @@ -839,7 +837,7 @@ BehaviorModuleOutput StartPlannerModule::planWaitingApproval() setDrivableAreaInfo(output); - const auto steering_factor_direction = getSteeringFactorDirection(output); + const auto planning_factor_direction = getPlanningFactorDirection(output); if (status_.driving_forward) { const double start_distance = autoware::motion_utils::calcSignedArcLength( @@ -849,10 +847,9 @@ BehaviorModuleOutput StartPlannerModule::planWaitingApproval() stop_path.points, planner_data_->self_odometry->pose.pose.position, status_.pull_out_path.end_pose.position); updateRTCStatus(start_distance, finish_distance); - steering_factor_interface_.set( - {status_.pull_out_path.start_pose, status_.pull_out_path.end_pose}, - {start_distance, finish_distance}, steering_factor_direction, SteeringFactor::APPROACHING, - ""); + planning_factor_interface_->add( + start_distance, finish_distance, status_.pull_out_path.start_pose, + status_.pull_out_path.end_pose, planning_factor_direction, SafetyFactorArray{}); setDebugData(); return output; @@ -861,9 +858,9 @@ BehaviorModuleOutput StartPlannerModule::planWaitingApproval() stop_path.points, planner_data_->self_odometry->pose.pose.position, status_.pull_out_path.start_pose.position); updateRTCStatus(0.0, distance); - steering_factor_interface_.set( - {status_.pull_out_path.start_pose, status_.pull_out_path.end_pose}, {0.0, distance}, - steering_factor_direction, SteeringFactor::APPROACHING, ""); + planning_factor_interface_->add( + 0.0, distance, status_.pull_out_path.start_pose, status_.pull_out_path.end_pose, + planning_factor_direction, SafetyFactorArray{}); setDebugData(); diff --git a/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/manager.hpp b/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/manager.hpp index 895390f91cc16..6296acd8e71f7 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/manager.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/manager.hpp @@ -41,7 +41,7 @@ class StaticObstacleAvoidanceModuleManager : public SceneModuleManagerInterface { return std::make_unique( name_, *node_, parameters_, rtc_interface_ptr_map_, - objects_of_interest_marker_interface_ptr_map_); + objects_of_interest_marker_interface_ptr_map_, planning_factor_interface_); } void updateModuleParams(const std::vector & parameters) override; diff --git a/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/scene.hpp b/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/scene.hpp index 5848cc75f148e..247e22e1aedad 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/scene.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/include/autoware/behavior_path_static_obstacle_avoidance_module/scene.hpp @@ -46,7 +46,8 @@ class StaticObstacleAvoidanceModule : public SceneModuleInterface const std::string & name, rclcpp::Node & node, std::shared_ptr parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map); + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr & planning_factor_interface); CandidateOutput planCandidate() const override; BehaviorModuleOutput plan() override; @@ -131,9 +132,9 @@ class StaticObstacleAvoidanceModule : public SceneModuleInterface } if (finish_distance > -1.0e-03) { - steering_factor_interface_.set( - {left_shift.start_pose, left_shift.finish_pose}, {start_distance, finish_distance}, - SteeringFactor::LEFT, SteeringFactor::TURNING, ""); + planning_factor_interface_->add( + start_distance, finish_distance, left_shift.start_pose, left_shift.finish_pose, + PlanningFactor::SHIFT_LEFT, SafetyFactorArray{}); } } @@ -151,9 +152,9 @@ class StaticObstacleAvoidanceModule : public SceneModuleInterface } if (finish_distance > -1.0e-03) { - steering_factor_interface_.set( - {right_shift.start_pose, right_shift.finish_pose}, {start_distance, finish_distance}, - SteeringFactor::RIGHT, SteeringFactor::TURNING, ""); + planning_factor_interface_->add( + start_distance, finish_distance, right_shift.start_pose, right_shift.finish_pose, + PlanningFactor::SHIFT_RIGHT, SafetyFactorArray{}); } } } diff --git a/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/src/scene.cpp b/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/src/scene.cpp index 48729c9c4fa0c..739b5b21f59dc 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/src/scene.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_static_obstacle_avoidance_module/src/scene.cpp @@ -79,14 +79,13 @@ StaticObstacleAvoidanceModule::StaticObstacleAvoidanceModule( const std::string & name, rclcpp::Node & node, std::shared_ptr parameters, const std::unordered_map> & rtc_interface_ptr_map, std::unordered_map> & - objects_of_interest_marker_interface_ptr_map) -: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT + objects_of_interest_marker_interface_ptr_map, + const std::shared_ptr & planning_factor_interface) +: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map, planning_factor_interface}, // NOLINT helper_{std::make_shared(parameters)}, parameters_{parameters}, generator_{parameters} { - steering_factor_interface_.init(PlanningBehavior::AVOIDANCE); - velocity_factor_interface_.init(PlanningBehavior::AVOIDANCE); } bool StaticObstacleAvoidanceModule::isExecutionRequested() const @@ -776,7 +775,7 @@ void StaticObstacleAvoidanceModule::updateEgoBehavior( insertReturnDeadLine(isBestEffort(parameters_->policy_deceleration), path); - setVelocityFactor(path.path); + set_longitudinal_planning_factor(path.path); } bool StaticObstacleAvoidanceModule::isSafePath( @@ -1209,13 +1208,12 @@ CandidateOutput StaticObstacleAvoidanceModule::planCandidate() const output.start_distance_to_path_change = sl_front.start_longitudinal; output.finish_distance_to_path_change = sl_back.end_longitudinal; - const uint16_t steering_factor_direction = std::invoke([&output]() { - return output.lateral_shift > 0.0 ? SteeringFactor::LEFT : SteeringFactor::RIGHT; + const uint16_t planning_factor_direction = std::invoke([&output]() { + return output.lateral_shift > 0.0 ? PlanningFactor::SHIFT_LEFT : PlanningFactor::SHIFT_RIGHT; }); - steering_factor_interface_.set( - {sl_front.start, sl_back.end}, - {output.start_distance_to_path_change, output.finish_distance_to_path_change}, - steering_factor_direction, SteeringFactor::APPROACHING, ""); + planning_factor_interface_->add( + output.start_distance_to_path_change, output.finish_distance_to_path_change, sl_front.start, + sl_back.end, planning_factor_direction, SafetyFactorArray{}, true, 0.0, output.lateral_shift); output.path_candidate = shifted_path.path; return output; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp index 5e8ef9fc8a063..91eff0b01346a 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp @@ -74,7 +74,9 @@ class BlindSpotModule : public SceneModuleInterfaceWithRTC BlindSpotModule( const int64_t module_id, const int64_t lane_id, const TurnDirection turn_direction, const std::shared_ptr planner_data, const PlannerParam & planner_param, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock); + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); /** * @brief plan go-stop velocity at traffic crossing with collision check between reference path diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/decisions.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/decisions.cpp index 64e1435167a89..a978c074e0018 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/decisions.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/decisions.cpp @@ -101,8 +101,11 @@ void BlindSpotModule::reactRTCApprovalByDecision( decision.stop_line_idx, planner_data_->vehicle_info_.max_longitudinal_offset_m, *path); const auto stop_pose = path->points.at(decision.stop_line_idx).point.pose; - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::UNKNOWN); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, + "blind_spot(module is judging as UNSAFE)"); } return; } @@ -132,8 +135,11 @@ void BlindSpotModule::reactRTCApprovalByDecision( decision.stop_line_idx, planner_data_->vehicle_info_.max_longitudinal_offset_m, *path); const auto stop_pose = path->points.at(decision.stop_line_idx).point.pose; - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::UNKNOWN); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, + "blind_spot(module is judging as SAFE and RTC is not approved)"); } return; } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/manager.cpp index d6cae9004600a..ee6516f025709 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/manager.cpp @@ -59,7 +59,7 @@ void BlindSpotModuleManager::launchNewModules(const tier4_planning_msgs::msg::Pa registerModule(std::make_shared( module_id, lane_id, turn_direction, planner_data_, planner_param_, - logger_.get_child("blind_spot_module"), clock_)); + logger_.get_child("blind_spot_module"), clock_, time_keeper_, planning_factor_interface_)); generateUUID(module_id); updateRTCStatus( getUUID(module_id), true, State::WAITING_FOR_EXECUTION, std::numeric_limits::lowest(), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp index 8a9401646aaea..4fca5f821f934 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp @@ -40,14 +40,15 @@ namespace bg = boost::geometry; BlindSpotModule::BlindSpotModule( const int64_t module_id, const int64_t lane_id, const TurnDirection turn_direction, const std::shared_ptr planner_data, const PlannerParam & planner_param, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterfaceWithRTC(module_id, logger, clock), + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), planner_param_{planner_param}, turn_direction_(turn_direction), is_over_pass_judge_line_(false) { - velocity_factor_.init(PlanningBehavior::REAR_CHECK); sibling_straight_lanelet_ = getSiblingStraightLanelet( planner_data->route_handler_->getLaneletMapPtr()->laneletLayer.get(lane_id_), planner_data->route_handler_->getRoutingGraphPtr()); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/manager.cpp index cdaff7225a7d2..5bfd31b75976a 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/manager.cpp @@ -192,8 +192,8 @@ void CrosswalkModuleManager::launchNewModules(const PathWithLaneId & path) // NOTE: module_id is always a lane id so that isModuleRegistered works correctly in the case // where both regulatory element and non-regulatory element crosswalks exist. registerModule(std::make_shared( - node_, road_lanelet_id, crosswalk_lanelet_id, reg_elem_id, lanelet_map_ptr, p, logger, - clock_)); + node_, road_lanelet_id, crosswalk_lanelet_id, reg_elem_id, lanelet_map_ptr, p, logger, clock_, + time_keeper_, planning_factor_interface_)); generateUUID(crosswalk_lanelet_id); updateRTCStatus( getUUID(crosswalk_lanelet_id), true, State::WAITING_FOR_EXECUTION, diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp index 64f7e9e14dcd1..844647e33f8c0 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp @@ -34,12 +34,12 @@ #include #include #include +#include #include #include #include #include #include - namespace autoware::behavior_velocity_planner { namespace bg = boost::geometry; @@ -175,13 +175,14 @@ CrosswalkModule::CrosswalkModule( rclcpp::Node & node, const int64_t lane_id, const int64_t module_id, const std::optional & reg_elem_id, const lanelet::LaneletMapPtr & lanelet_map_ptr, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterfaceWithRTC(module_id, logger, clock), + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), module_id_(module_id), planner_param_(planner_param), use_regulatory_element_(reg_elem_id) { - velocity_factor_.init(PlanningBehavior::CROSSWALK); passed_safety_slow_point_ = false; if (use_regulatory_element_) { @@ -898,9 +899,11 @@ void CrosswalkModule::applySlowDown( } } if (slowdown_pose) - velocity_factor_.set( - output.points, planner_data_->current_odometry->pose, *slowdown_pose, - VelocityFactor::APPROACHING); + planning_factor_interface_->add( + output.points, planner_data_->current_odometry->pose, *slowdown_pose, *slowdown_pose, + tier4_planning_msgs::msg::PlanningFactor::SLOW_DOWN, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, + safety_slow_down_speed, 0.0 /*shift distance*/, "crosswalk_safety_slowdown_for_approaching"); } void CrosswalkModule::applySlowDownByLanelet2Map( @@ -1377,9 +1380,11 @@ void CrosswalkModule::planStop( // Plan stop insertDecelPointWithDebugInfo(stop_factor->stop_pose.position, 0.0, ego_path); - velocity_factor_.set( + planning_factor_interface_->add( ego_path.points, planner_data_->current_odometry->pose, stop_factor->stop_pose, - VelocityFactor::UNKNOWN); + stop_factor->stop_pose, tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0 /*velocity*/, + 0.0 /*shift distance*/, "crosswalk_stop"); } bool CrosswalkModule::checkRestartSuppression( diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp index d5a9e463c730b..f32ee96623822 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp @@ -334,7 +334,9 @@ class CrosswalkModule : public SceneModuleInterfaceWithRTC rclcpp::Node & node, const int64_t lane_id, const int64_t module_id, const std::optional & reg_elem_id, const lanelet::LaneletMapPtr & lanelet_map_ptr, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock); + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/manager.cpp index fb2c17d9e3745..f231d7adc3326 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/manager.cpp @@ -64,7 +64,8 @@ void DetectionAreaModuleManager::launchNewModules( if (!isModuleRegistered(module_id)) { registerModule(std::make_shared( module_id, lane_id, *detection_area_with_lane_id.first, planner_param_, - logger_.get_child("detection_area_module"), clock_)); + logger_.get_child("detection_area_module"), clock_, time_keeper_, + planning_factor_interface_)); } } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp index 031c45753022e..59f6f20937f41 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp @@ -36,8 +36,10 @@ DetectionAreaModule::DetectionAreaModule( const int64_t module_id, const int64_t lane_id, const lanelet::autoware::DetectionArea & detection_area_reg_elem, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), detection_area_reg_elem_(detection_area_reg_elem), state_(State::GO), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp index 9224cf4624687..1d3e5f3540ff3 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp @@ -68,7 +68,9 @@ class DetectionAreaModule : public SceneModuleInterface const int64_t module_id, const int64_t lane_id, const lanelet::autoware::DetectionArea & detection_area_reg_elem, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock); + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/manager.cpp index 41bdbe3e43c8b..d6f7dfbac92d4 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/manager.cpp @@ -338,7 +338,8 @@ void IntersectionModuleManager::launchNewModules( } const auto new_module = std::make_shared( module_id, lane_id, planner_data_, intersection_param_, associative_ids, turn_direction, - has_traffic_light, node_, logger_.get_child("intersection_module"), clock_); + has_traffic_light, node_, logger_.get_child("intersection_module"), clock_, time_keeper_, + planning_factor_interface_); generateUUID(module_id); /* set RTC status as non_occluded status initially */ const UUID uuid = getUUID(new_module->getModuleId()); @@ -526,7 +527,8 @@ void MergeFromPrivateModuleManager::launchNewModules( planning_utils::getAssociativeIntersectionLanelets(ll, lanelet_map, routing_graph); registerModule(std::make_shared( module_id, lane_id, planner_data_, merge_from_private_area_param_, associative_ids, - logger_.get_child("merge_from_private_road_module"), clock_)); + logger_.get_child("merge_from_private_road_module"), clock_, time_keeper_, + planning_factor_interface_)); continue; } } else { @@ -540,7 +542,8 @@ void MergeFromPrivateModuleManager::launchNewModules( planning_utils::getAssociativeIntersectionLanelets(ll, lanelet_map, routing_graph); registerModule(std::make_shared( module_id, lane_id, planner_data_, merge_from_private_area_param_, associative_ids, - logger_.get_child("merge_from_private_road_module"), clock_)); + logger_.get_child("merge_from_private_road_module"), clock_, time_keeper_, + planning_factor_interface_)); continue; } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp index 93a13a4d62737..2d5da0f070ed9 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp @@ -18,7 +18,6 @@ #include // for toGeomPoly #include -#include #include #include // for toPolygon2d #include @@ -52,8 +51,10 @@ IntersectionModule::IntersectionModule( [[maybe_unused]] std::shared_ptr planner_data, const PlannerParam & planner_param, const std::set & associative_ids, const std::string & turn_direction, const bool has_traffic_light, rclcpp::Node & node, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterfaceWithRTC(module_id, logger, clock), + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), planner_param_(planner_param), lane_id_(lane_id), associative_ids_(associative_ids), @@ -61,8 +62,6 @@ IntersectionModule::IntersectionModule( has_traffic_light_(has_traffic_light), occlusion_uuid_(autoware::universe_utils::generateUUID()) { - velocity_factor_.init(PlanningBehavior::INTERSECTION); - { collision_state_machine_.setMarginTime( planner_param_.collision_detection.collision_detection_hold_time); @@ -705,7 +704,7 @@ void reactRTCApprovalByDecisionResult( [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, [[maybe_unused]] const double baselink2front, [[maybe_unused]] tier4_planning_msgs::msg::PathWithLaneId * path, - [[maybe_unused]] VelocityFactorInterface * velocity_factor, + [[maybe_unused]] motion_utils::PlanningFactorInterface * planning_factor_interface, [[maybe_unused]] IntersectionModule::DebugData * debug_data) { static_assert("Unsupported type passed to reactRTCByDecisionResult"); @@ -720,7 +719,7 @@ void reactRTCApprovalByDecisionResult( [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, [[maybe_unused]] const double baselink2front, [[maybe_unused]] tier4_planning_msgs::msg::PathWithLaneId * path, - [[maybe_unused]] VelocityFactorInterface * velocity_factor, + [[maybe_unused]] motion_utils::PlanningFactorInterface * planning_factor_interface, [[maybe_unused]] IntersectionModule::DebugData * debug_data) { return; @@ -734,7 +733,7 @@ void reactRTCApprovalByDecisionResult( [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, [[maybe_unused]] const double baselink2front, [[maybe_unused]] tier4_planning_msgs::msg::PathWithLaneId * path, - [[maybe_unused]] VelocityFactorInterface * velocity_factor, + [[maybe_unused]] motion_utils::PlanningFactorInterface * planning_factor_interface, [[maybe_unused]] IntersectionModule::DebugData * debug_data) { return; @@ -746,7 +745,8 @@ void reactRTCApprovalByDecisionResult( const StuckStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - VelocityFactorInterface * velocity_factor, IntersectionModule::DebugData * debug_data) + motion_utils::PlanningFactorInterface * planning_factor_interface, + IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( rclcpp::get_logger("reactRTCApprovalByDecisionResult"), @@ -760,9 +760,12 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(pure StuckStop)"); } } if (!rtc_occlusion_approved && decision_result.occlusion_stopline_idx) { @@ -771,9 +774,13 @@ void reactRTCApprovalByDecisionResult( debug_data->occlusion_stop_wall_pose = planning_utils::getAheadPose(occlusion_stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(closest_idx).point.pose, - path->points.at(occlusion_stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(occlusion_stopline_idx).point.pose, + path->points.at(occlusion_stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(StuckStop with occlusion)"); } } return; @@ -785,7 +792,8 @@ void reactRTCApprovalByDecisionResult( const YieldStuckStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - VelocityFactorInterface * velocity_factor, IntersectionModule::DebugData * debug_data) + motion_utils::PlanningFactorInterface * planning_factor_interface, + IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( rclcpp::get_logger("reactRTCApprovalByDecisionResult"), @@ -799,9 +807,12 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(Yield Stuck)"); } } return; @@ -813,7 +824,8 @@ void reactRTCApprovalByDecisionResult( const NonOccludedCollisionStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - VelocityFactorInterface * velocity_factor, IntersectionModule::DebugData * debug_data) + motion_utils::PlanningFactorInterface * planning_factor_interface, + IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( rclcpp::get_logger("reactRTCApprovalByDecisionResult"), @@ -825,9 +837,12 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(CollisionStop)"); } } if (!rtc_occlusion_approved) { @@ -836,9 +851,12 @@ void reactRTCApprovalByDecisionResult( debug_data->occlusion_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(CollisionStop with occlusion)"); } } return; @@ -849,7 +867,8 @@ void reactRTCApprovalByDecisionResult( const bool rtc_default_approved, const bool rtc_occlusion_approved, const FirstWaitBeforeOcclusion & decision_result, const IntersectionModule::PlannerParam & planner_param, const double baselink2front, - tier4_planning_msgs::msg::PathWithLaneId * path, VelocityFactorInterface * velocity_factor, + tier4_planning_msgs::msg::PathWithLaneId * path, + motion_utils::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -862,9 +881,12 @@ void reactRTCApprovalByDecisionResult( debug_data->occlusion_first_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(FirstWaitBeforeOcclusion with collision)"); } } if (!rtc_occlusion_approved) { @@ -881,9 +903,12 @@ void reactRTCApprovalByDecisionResult( debug_data->occlusion_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(FirstWaitBeforeOcclusion with occlusion)"); } } return; @@ -894,7 +919,8 @@ void reactRTCApprovalByDecisionResult( const bool rtc_default_approved, const bool rtc_occlusion_approved, const PeekingTowardOcclusion & decision_result, const IntersectionModule::PlannerParam & planner_param, const double baselink2front, - tier4_planning_msgs::msg::PathWithLaneId * path, VelocityFactorInterface * velocity_factor, + tier4_planning_msgs::msg::PathWithLaneId * path, + motion_utils::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -920,9 +946,13 @@ void reactRTCApprovalByDecisionResult( debug_data->static_occlusion_with_traffic_light_timeout = decision_result.static_occlusion_timeout; { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(occlusion_peeking_stopline).point.pose, VelocityFactor::UNKNOWN); + path->points.at(occlusion_peeking_stopline).point.pose, + path->points.at(occlusion_peeking_stopline).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(PeekingToOcclusion)"); } } if (!rtc_default_approved) { @@ -931,9 +961,12 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(PeekingToOcclusion while stopping for collision)"); } } return; @@ -945,7 +978,8 @@ void reactRTCApprovalByDecisionResult( const OccludedCollisionStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - VelocityFactorInterface * velocity_factor, IntersectionModule::DebugData * debug_data) + motion_utils::PlanningFactorInterface * planning_factor_interface, + IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( rclcpp::get_logger("reactRTCApprovalByDecisionResult"), @@ -957,9 +991,12 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(CollisionStop with occlusion)"); } } if (!rtc_occlusion_approved) { @@ -972,9 +1009,12 @@ void reactRTCApprovalByDecisionResult( debug_data->static_occlusion_with_traffic_light_timeout = decision_result.static_occlusion_timeout; { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(CollisionStop with occlusion)"); } } return; @@ -986,7 +1026,8 @@ void reactRTCApprovalByDecisionResult( const OccludedAbsenceTrafficLight & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - VelocityFactorInterface * velocity_factor, IntersectionModule::DebugData * debug_data) + motion_utils::PlanningFactorInterface * planning_factor_interface, + IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( rclcpp::get_logger("reactRTCApprovalByDecisionResult"), @@ -998,9 +1039,13 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, + "intersection(Occlusion without traffic light, collision detected)"); } } if (!rtc_occlusion_approved && decision_result.temporal_stop_before_attention_required) { @@ -1009,9 +1054,12 @@ void reactRTCApprovalByDecisionResult( debug_data->occlusion_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(Occlusion without traffic light)"); } } if (!rtc_occlusion_approved && !decision_result.temporal_stop_before_attention_required) { @@ -1032,7 +1080,8 @@ void reactRTCApprovalByDecisionResult( const bool rtc_default_approved, const bool rtc_occlusion_approved, const Safe & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - VelocityFactorInterface * velocity_factor, IntersectionModule::DebugData * debug_data) + motion_utils::PlanningFactorInterface * planning_factor_interface, + IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( rclcpp::get_logger("reactRTCApprovalByDecisionResult"), @@ -1043,9 +1092,12 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(Safe, but RTC interrupted for collision)"); } } if (!rtc_occlusion_approved) { @@ -1054,9 +1106,12 @@ void reactRTCApprovalByDecisionResult( debug_data->occlusion_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(Safe, but RTC interrupted for occlusion)"); } } return; @@ -1068,7 +1123,8 @@ void reactRTCApprovalByDecisionResult( const FullyPrioritized & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - VelocityFactorInterface * velocity_factor, IntersectionModule::DebugData * debug_data) + motion_utils::PlanningFactorInterface * planning_factor_interface, + IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( rclcpp::get_logger("reactRTCApprovalByDecisionResult"), @@ -1080,9 +1136,12 @@ void reactRTCApprovalByDecisionResult( debug_data->collision_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, "intersection(FullyPrioritized, collision detected)"); } } if (!rtc_occlusion_approved) { @@ -1091,9 +1150,13 @@ void reactRTCApprovalByDecisionResult( debug_data->occlusion_stop_wall_pose = planning_utils::getAheadPose(stopline_idx, baselink2front, *path); { - velocity_factor->set( + planning_factor_interface->add( path->points, path->points.at(decision_result.closest_idx).point.pose, - path->points.at(stopline_idx).point.pose, VelocityFactor::UNKNOWN); + path->points.at(stopline_idx).point.pose, path->points.at(stopline_idx).point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, + "intersection(FullyPrioritized, RTC for occlusion is interrupting)"); } } return; @@ -1107,7 +1170,7 @@ void IntersectionModule::reactRTCApproval( VisitorSwitch{[&](const auto & decision) { reactRTCApprovalByDecisionResult( activated_, occlusion_activated_, decision, planner_param_, baselink2front, path, - &velocity_factor_, &debug_data_); + planning_factor_interface_.get(), &debug_data_); }}, decision_result); return; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp index 6c31be2ce83b9..db0cfbe98d53c 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp @@ -304,7 +304,9 @@ class IntersectionModule : public SceneModuleInterfaceWithRTC const int64_t module_id, const int64_t lane_id, std::shared_ptr planner_data, const PlannerParam & planner_param, const std::set & associative_ids, const std::string & turn_direction, const bool has_traffic_light, rclcpp::Node & node, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock); + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); /** *********************************************************** diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp index 3dfdcc36c0cff..fc442337198af 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp @@ -41,12 +41,13 @@ MergeFromPrivateRoadModule::MergeFromPrivateRoadModule( const int64_t module_id, const int64_t lane_id, [[maybe_unused]] std::shared_ptr planner_data, const PlannerParam & planner_param, const std::set & associative_ids, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), associative_ids_(associative_ids) { - velocity_factor_.init(PlanningBehavior::MERGE); planner_param_ = planner_param; state_machine_.setState(StateMachine::State::STOP); } @@ -153,8 +154,10 @@ bool MergeFromPrivateRoadModule::modifyPathVelocity(PathWithLaneId * path) /* get stop point and stop factor */ const auto & stop_pose = path->points.at(stopline_idx).point.pose; - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::UNKNOWN); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, "merge_from_private"); const double signed_arc_dist_to_stop_point = autoware::motion_utils::calcSignedArcLength( path->points, current_pose.position, path->points.at(stopline_idx).point.pose.position); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp index dc8bf1a96a7a2..fe446d304d9e0 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp @@ -61,7 +61,9 @@ class MergeFromPrivateRoadModule : public SceneModuleInterface MergeFromPrivateRoadModule( const int64_t module_id, const int64_t lane_id, std::shared_ptr planner_data, const PlannerParam & planner_param, const std::set & associative_ids, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock); + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); /** * @brief plan go-stop velocity at traffic crossing with collision check between reference path diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/manager.cpp index 9cb1153a8edd2..517568c93bd35 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/manager.cpp @@ -51,7 +51,8 @@ void NoDrivableLaneModuleManager::launchNewModules( } registerModule(std::make_shared( - module_id, lane_id, planner_param_, logger_.get_child("no_drivable_lane_module"), clock_)); + module_id, lane_id, planner_param_, logger_.get_child("no_drivable_lane_module"), clock_, + time_keeper_, planning_factor_interface_)); } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp index 8365251904b18..f32210bc502bf 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp @@ -21,14 +21,18 @@ #include #include +#include + namespace autoware::behavior_velocity_planner { using autoware::universe_utils::createPoint; NoDrivableLaneModule::NoDrivableLaneModule( const int64_t module_id, const int64_t lane_id, const PlannerParam & planner_param, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), planner_param_(planner_param), debug_data_(), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp index d8c5e3e0425d1..835e946443e90 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp @@ -55,7 +55,9 @@ class NoDrivableLaneModule : public SceneModuleInterface NoDrivableLaneModule( const int64_t module_id, const int64_t lane_id, const PlannerParam & planner_param, - const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock); + const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/manager.cpp index dca2dde33b693..55b6c0dffd1a4 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/manager.cpp @@ -60,7 +60,7 @@ void NoStoppingAreaModuleManager::launchNewModules( // assign 1 no stopping area for each module registerModule(std::make_shared( module_id, lane_id, *m.first, planner_param_, logger_.get_child("no_stopping_area_module"), - clock_)); + clock_, time_keeper_, planning_factor_interface_)); generateUUID(module_id); updateRTCStatus( getUUID(module_id), true, State::WAITING_FOR_EXECUTION, diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp index 5c79ec69a9d98..bcb8b365f6205 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp @@ -30,6 +30,7 @@ #include #include +#include #include namespace autoware::behavior_velocity_planner @@ -40,8 +41,10 @@ NoStoppingAreaModule::NoStoppingAreaModule( const int64_t module_id, const int64_t lane_id, const lanelet::autoware::NoStoppingArea & no_stopping_area_reg_elem, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterfaceWithRTC(module_id, logger, clock), + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), no_stopping_area_reg_elem_(no_stopping_area_reg_elem), planner_param_(planner_param), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp index 1eafcf157623d..0d53441924805 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp @@ -57,7 +57,9 @@ class NoStoppingAreaModule : public SceneModuleInterfaceWithRTC const int64_t module_id, const int64_t lane_id, const lanelet::autoware::NoStoppingArea & no_stopping_area_reg_elem, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock); + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/manager.cpp index c4dace9d49244..d28cff55a7a8d 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/manager.cpp @@ -123,8 +123,8 @@ void OcclusionSpotModuleManager::launchNewModules( // general if (!isModuleRegistered(module_id_)) { registerModule(std::make_shared( - module_id_, planner_data_, planner_param_, logger_.get_child("occlusion_spot_module"), - clock_)); + module_id_, planner_data_, planner_param_, logger_.get_child("occlusion_spot_module"), clock_, + time_keeper_, planning_factor_interface_)); } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp index c5d1cf61614b2..1163b00e08ccb 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp @@ -64,8 +64,11 @@ namespace utils = occlusion_spot_utils; OcclusionSpotModule::OcclusionSpotModule( const int64_t module_id, const std::shared_ptr & planner_data, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), param_(planner_param) + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), + param_(planner_param) { velocity_factor_.init(PlanningBehavior::UNKNOWN); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp index 35c409a9c459b..22b2a91be66b0 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp @@ -48,7 +48,9 @@ class OcclusionSpotModule : public SceneModuleInterface OcclusionSpotModule( const int64_t module_id, const std::shared_ptr & planner_data, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock); + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); /** * @brief plan occlusion spot velocity at unknown area in occupancy grid diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp index a891b011dbab8..ad1ae1d47664a 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -79,7 +80,9 @@ class SceneModuleInterface { public: explicit SceneModuleInterface( - const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock); + const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); virtual ~SceneModuleInterface() = default; virtual bool modifyPathVelocity(PathWithLaneId * path) = 0; @@ -94,13 +97,6 @@ class SceneModuleInterface planner_data_ = planner_data; } - void setTimeKeeper(const std::shared_ptr & time_keeper) - { - time_keeper_ = time_keeper; - } - - std::shared_ptr getTimeKeeper() { return time_keeper_; } - void resetVelocityFactor() { velocity_factor_.reset(); } VelocityFactor getVelocityFactor() const { return velocity_factor_.get(); } std::vector getObjectsOfInterestData() const { return objects_of_interest_; } @@ -111,9 +107,10 @@ class SceneModuleInterface rclcpp::Logger logger_; rclcpp::Clock::SharedPtr clock_; std::shared_ptr planner_data_; - autoware::motion_utils::VelocityFactorInterface velocity_factor_; + autoware::motion_utils::VelocityFactorInterface velocity_factor_; // TODO(soblin): remove this std::vector objects_of_interest_; mutable std::shared_ptr time_keeper_; + std::shared_ptr planning_factor_interface_; void setObjectsOfInterestData( const geometry_msgs::msg::Pose & pose, const autoware_perception_msgs::msg::Shape & shape, @@ -148,6 +145,8 @@ class SceneModuleManagerInterface std::string("~/virtual_wall/") + module_name, 5); pub_velocity_factor_ = node.create_publisher( std::string("/planning/velocity_factors/") + module_name, 1); + planning_factor_interface_ = + std::make_shared(&node, module_name); processing_time_publisher_ = std::make_shared(&node, "~/debug"); @@ -191,6 +190,7 @@ class SceneModuleManagerInterface scene_module->modifyPathVelocity(path); // The velocity factor must be called after modifyPathVelocity. + // TODO(soblin): remove this const auto velocity_factor = scene_module->getVelocityFactor(); if (velocity_factor.behavior != PlanningBehavior::UNKNOWN) { velocity_factor_array.factors.emplace_back(velocity_factor); @@ -204,6 +204,7 @@ class SceneModuleManagerInterface } pub_velocity_factor_->publish(velocity_factor_array); + planning_factor_interface_->publish(); pub_debug_->publish(debug_marker_array); if (is_publish_debug_path_) { tier4_planning_msgs::msg::PathWithLaneId debug_path; @@ -247,7 +248,6 @@ class SceneModuleManagerInterface logger_, "register task: module = %s, id = %lu", getModuleName(), scene_module->getModuleId()); registered_module_id_set_.emplace(scene_module->getModuleId()); - scene_module->setTimeKeeper(time_keeper_); scene_modules_.insert(scene_module); } @@ -282,6 +282,8 @@ class SceneModuleManagerInterface rclcpp::Publisher::SharedPtr pub_processing_time_detail_; std::shared_ptr time_keeper_; + + std::shared_ptr planning_factor_interface_; }; extern template SceneModuleManagerInterface::SceneModuleManagerInterface( rclcpp::Node & node, [[maybe_unused]] const char * module_name); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp index ffd454012d13e..db2a274272f9f 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp @@ -25,11 +25,14 @@ namespace autoware::behavior_velocity_planner { SceneModuleInterface::SceneModuleInterface( - const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock) + const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) : module_id_(module_id), logger_(logger), clock_(clock), - time_keeper_(std::shared_ptr()) + time_keeper_(time_keeper), + planning_factor_interface_(planning_factor_interface) { } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp index 4e30ab019aa4e..a955538f4f9fe 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp @@ -52,7 +52,9 @@ class SceneModuleInterfaceWithRTC : public SceneModuleInterface { public: explicit SceneModuleInterfaceWithRTC( - const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock); + const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); virtual ~SceneModuleInterfaceWithRTC() = default; void setActivation(const bool activated) { activated_ = activated; } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp index abac509fd2b2b..2e73b35e20ed9 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp @@ -27,8 +27,10 @@ namespace autoware::behavior_velocity_planner { SceneModuleInterfaceWithRTC::SceneModuleInterfaceWithRTC( - const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), activated_(false), safe_(false), distance_(std::numeric_limits::lowest()) diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/manager.cpp index 4a16f263d0a54..4af7882461643 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/manager.cpp @@ -156,7 +156,8 @@ void RunOutModuleManager::launchNewModules(const tier4_planning_msgs::msg::PathW if (!isModuleRegistered(module_id)) { registerModule(std::make_shared( module_id, planner_data_, planner_param_, logger_.get_child("run_out_module"), - std::move(dynamic_obstacle_creator_), debug_ptr_, clock_)); + std::move(dynamic_obstacle_creator_), debug_ptr_, clock_, time_keeper_, + planning_factor_interface_)); } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp index efc2d458ae2a7..193ba5eab0553 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp @@ -45,15 +45,15 @@ RunOutModule::RunOutModule( const int64_t module_id, const std::shared_ptr & planner_data, const PlannerParam & planner_param, const rclcpp::Logger logger, std::unique_ptr dynamic_obstacle_creator, - const std::shared_ptr & debug_ptr, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const std::shared_ptr & debug_ptr, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), planner_param_(planner_param), dynamic_obstacle_creator_(std::move(dynamic_obstacle_creator)), debug_ptr_(debug_ptr), state_machine_(std::make_unique(planner_param.approaching.state)) { - velocity_factor_.init(PlanningBehavior::RUN_OUT); - if (planner_param.run_out.use_partition_lanelet) { const lanelet::LaneletMapConstPtr & ll = planner_data->route_handler_->getLaneletMapPtr(); planning_utils::getAllPartitionLanelets(ll, partition_lanelets_); @@ -770,9 +770,10 @@ bool RunOutModule::insertStopPoint( stop_point_with_lane_id.point.pose = *stop_point; planning_utils::insertVelocity(path, stop_point_with_lane_id, 0.0, insert_idx); - velocity_factor_.set( - path.points, planner_data_->current_odometry->pose, stop_point.value(), VelocityFactor::UNKNOWN, - "run_out"); + planning_factor_interface_->add( + path.points, planner_data_->current_odometry->pose, stop_point.value(), stop_point.value(), + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0 /*velocity*/, 0.0 /*shift_distance*/, "run_out_stop"); return true; } @@ -876,8 +877,11 @@ void RunOutModule::insertApproachingVelocity( return; } - velocity_factor_.set( - output_path.points, current_pose, stop_point.value(), VelocityFactor::UNKNOWN, "run_out"); + planning_factor_interface_->add( + output_path.points, planner_data_->current_odometry->pose, stop_point.value(), + stop_point.value(), tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0 /*velocity*/, + 0.0 /*shift_distance*/, "run_out_approaching_velocity"); // debug debug_ptr_->pushStopPose(autoware::universe_utils::calcOffsetPose( diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp index 83123c71f461e..49de16753a869 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp @@ -47,7 +47,9 @@ class RunOutModule : public SceneModuleInterface const int64_t module_id, const std::shared_ptr & planner_data, const PlannerParam & planner_param, const rclcpp::Logger logger, std::unique_ptr dynamic_obstacle_creator, - const std::shared_ptr & debug_ptr, const rclcpp::Clock::SharedPtr clock); + const std::shared_ptr & debug_ptr, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/manager.cpp index 4677d49b78f4b..a69e33e9e0391 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/manager.cpp @@ -63,7 +63,7 @@ void SpeedBumpModuleManager::launchNewModules(const tier4_planning_msgs::msg::Pa if (!isModuleRegistered(module_id)) { registerModule(std::make_shared( module_id, lane_id, *speed_bump_with_lane_id.first, planner_param_, - logger_.get_child("speed_bump_module"), clock_)); + logger_.get_child("speed_bump_module"), clock_, time_keeper_, planning_factor_interface_)); } } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp index 54ea807f3268b..4af7801e50ba3 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp @@ -21,6 +21,7 @@ #include #include +#include #include namespace autoware::behavior_velocity_planner @@ -33,8 +34,10 @@ using geometry_msgs::msg::Point32; SpeedBumpModule::SpeedBumpModule( const int64_t module_id, const int64_t lane_id, const lanelet::autoware::SpeedBump & speed_bump_reg_elem, const PlannerParam & planner_param, - const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), module_id_(module_id), lane_id_(lane_id), speed_bump_reg_elem_(std::move(speed_bump_reg_elem)), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp index 176a01d5112c5..e3ee2c0566381 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -54,7 +55,9 @@ class SpeedBumpModule : public SceneModuleInterface SpeedBumpModule( const int64_t module_id, const int64_t lane_id, const lanelet::autoware::SpeedBump & speed_bump_reg_elem, const PlannerParam & planner_param, - const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock); + const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/manager.cpp index b305a1d2aa404..e289779df34b6 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/manager.cpp @@ -81,7 +81,7 @@ void StopLineModuleManager::launchNewModules(const tier4_planning_msgs::msg::Pat if (!isModuleRegistered(module_id)) { registerModule(std::make_shared( module_id, stop_line_with_lane_id.first, planner_param_, - logger_.get_child("stop_line_module"), clock_)); + logger_.get_child("stop_line_module"), clock_, time_keeper_, planning_factor_interface_)); } } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp index 2a9c5dab1ebd9..71a5ea3b9e807 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp @@ -20,6 +20,7 @@ #include +#include #include #include @@ -28,8 +29,10 @@ namespace autoware::behavior_velocity_planner StopLineModule::StopLineModule( const int64_t module_id, lanelet::ConstLineString3d stop_line, const PlannerParam & planner_param, - const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), stop_line_(std::move(stop_line)), planner_param_(planner_param), state_(State::APPROACH), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp index 9ac1463da8618..aac830b0e9f24 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp @@ -30,6 +30,7 @@ #include +#include #include #include @@ -68,7 +69,9 @@ class StopLineModule : public SceneModuleInterface StopLineModule( const int64_t module_id, lanelet::ConstLineString3d stop_line, const PlannerParam & planner_param, const rclcpp::Logger & logger, - const rclcpp::Clock::SharedPtr clock); + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp index 1eafb71eb403c..e304b479a005d 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp @@ -74,7 +74,10 @@ class StopLineModuleTest : public ::testing::Test clock_ = std::make_shared(); module_ = std::make_shared( - 1, stop_line_, planner_param_, rclcpp::get_logger("test_logger"), clock_); + 1, stop_line_, planner_param_, rclcpp::get_logger("test_logger"), clock_, + std::make_shared(), + std::make_shared( + node_.get(), "test_stopline")); module_->setPlannerData(planner_data_); } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/manager.cpp index 4325cc1d5aaf9..a004f5b823138 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/manager.cpp @@ -42,8 +42,9 @@ void TemplateModuleManager::launchNewModules( { int64_t module_id = 0; if (!isModuleRegistered(module_id)) { - registerModule( - std::make_shared(module_id, logger_.get_child(getModuleName()), clock_)); + registerModule(std::make_shared( + module_id, logger_.get_child(getModuleName()), clock_, time_keeper_, + planning_factor_interface_)); } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp index 3ce8502baaf63..d8eea337e7186 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp @@ -19,14 +19,17 @@ #include +#include #include namespace autoware::behavior_velocity_planner { TemplateModule::TemplateModule( - const int64_t module_id, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock) + const int64_t module_id, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface) { } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp index 70cd5cb1235e7..ba078f3fd6421 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp @@ -18,9 +18,9 @@ #include #include +#include #include #include - namespace autoware::behavior_velocity_planner { using tier4_planning_msgs::msg::PathWithLaneId; @@ -29,7 +29,9 @@ class TemplateModule : public SceneModuleInterface { public: TemplateModule( - const int64_t module_id, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock); + const int64_t module_id, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); /** * @brief Modify the velocity of path points. diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp index 1b66824d04623..9a402f31af0e4 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp @@ -114,7 +114,8 @@ void TrafficLightModuleManager::launchNewModules( if (!isModuleRegisteredFromExistingAssociatedModule(lane_id)) { registerModule(std::make_shared( lane_id, *(traffic_light_reg_elem.first), traffic_light_reg_elem.second, planner_param_, - logger_.get_child("traffic_light_module"), clock_)); + logger_.get_child("traffic_light_module"), clock_, time_keeper_, + planning_factor_interface_)); generateUUID(lane_id); updateRTCStatus( getUUID(lane_id), true, State::WAITING_FOR_EXECUTION, std::numeric_limits::lowest(), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp index 458d8e1588a5b..b051d5ff7eb76 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp @@ -43,8 +43,10 @@ namespace autoware::behavior_velocity_planner TrafficLightModule::TrafficLightModule( const int64_t lane_id, const lanelet::TrafficLight & traffic_light_reg_elem, lanelet::ConstLanelet lane, const PlannerParam & planner_param, const rclcpp::Logger logger, - const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterfaceWithRTC(lane_id, logger, clock), + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterfaceWithRTC(lane_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), traffic_light_reg_elem_(traffic_light_reg_elem), lane_(lane), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp index 3af13bc1927ce..c30cbbdfc1477 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp @@ -69,7 +69,9 @@ class TrafficLightModule : public SceneModuleInterfaceWithRTC TrafficLightModule( const int64_t lane_id, const lanelet::TrafficLight & traffic_light_reg_elem, lanelet::ConstLanelet lane, const PlannerParam & planner_param, const rclcpp::Logger logger, - const rclcpp::Clock::SharedPtr clock); + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/manager.cpp index 3815c83d3b6ab..dade98dfc1133 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/manager.cpp @@ -94,7 +94,8 @@ void VirtualTrafficLightModuleManager::launchNewModules( ego_path_linestring, lanelet::utils::to2D(stop_line_opt.value()).basicLineString())) { registerModule(std::make_shared( module_id, lane_id, *m.first, m.second, planner_param_, - logger_.get_child("virtual_traffic_light_module"), clock_)); + logger_.get_child("virtual_traffic_light_module"), clock_, time_keeper_, + planning_factor_interface_)); } } } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp index 86239816ed6f2..9ba7b0bccf1b9 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -38,8 +39,10 @@ VirtualTrafficLightModule::VirtualTrafficLightModule( const int64_t module_id, const int64_t lane_id, const lanelet::autoware::VirtualTrafficLight & reg_elem, lanelet::ConstLanelet lane, const PlannerParam & planner_param, const rclcpp::Logger logger, - const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), reg_elem_(reg_elem), lane_(lane), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp index 7f37e7078a431..9e7a1192d9869 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -81,7 +82,9 @@ class VirtualTrafficLightModule : public SceneModuleInterface const int64_t module_id, const int64_t lane_id, const lanelet::autoware::VirtualTrafficLight & reg_elem, lanelet::ConstLanelet lane, const PlannerParam & planner_param, const rclcpp::Logger logger, - const rclcpp::Clock::SharedPtr clock); + const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/manager.cpp index 0f1a7509043b5..bfa8a96531090 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/manager.cpp @@ -61,7 +61,8 @@ void WalkwayModuleManager::launchNewModules(const PathWithLaneId & path) const auto lanelet_map_ptr = planner_data_->route_handler_->getLaneletMapPtr(); registerModule(std::make_shared( - lanelet.id(), lanelet_map_ptr, p, use_regulatory_element, logger, clock_)); + lanelet.id(), lanelet_map_ptr, p, use_regulatory_element, logger, clock_, time_keeper_, + planning_factor_interface_)); }; const auto crosswalk_leg_elem_map = planning_utils::getRegElemMapOnPath( diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp index 6a7505930a334..94421ae27e077 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp @@ -18,6 +18,7 @@ #include #include +#include #include namespace autoware::behavior_velocity_planner @@ -32,15 +33,15 @@ using autoware::universe_utils::getPose; WalkwayModule::WalkwayModule( const int64_t module_id, const lanelet::LaneletMapPtr & lanelet_map_ptr, const PlannerParam & planner_param, const bool use_regulatory_element, - const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock) -: SceneModuleInterface(module_id, logger, clock), + const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface) +: SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), module_id_(module_id), state_(State::APPROACH), planner_param_(planner_param), use_regulatory_element_(use_regulatory_element) { - velocity_factor_.init(PlanningBehavior::SIDEWALK); - if (use_regulatory_element_) { const auto reg_elem_ptr = std::dynamic_pointer_cast( lanelet_map_ptr->regulatoryElementLayer.get(module_id)); @@ -119,9 +120,10 @@ bool WalkwayModule::modifyPathVelocity(PathWithLaneId * path) } /* get stop point and stop factor */ - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose.value(), - VelocityFactor::UNKNOWN); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose.value(), stop_pose.value(), + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0 /*velocity*/, 0.0 /*shift distance*/, "walkway_stop"); // use arc length to identify if ego vehicle is in front of walkway stop or not. const double signed_arc_dist_to_stop_point = diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp index df54eafd11cc2..1bd5003498d34 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp @@ -44,7 +44,9 @@ class WalkwayModule : public SceneModuleInterface WalkwayModule( const int64_t module_id, const lanelet::LaneletMapPtr & lanelet_map_ptr, const PlannerParam & planner_param, const bool use_regulatory_element, - const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock); + const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, + const std::shared_ptr time_keeper, + const std::shared_ptr planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp index 7fd5834ba2cfa..2000615b51e2c 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp @@ -43,7 +43,9 @@ void DynamicObstacleStopModule::init(rclcpp::Node & node, const std::string & mo module_name_ = module_name; logger_ = node.get_logger().get_child(ns_); clock_ = node.get_clock(); - velocity_factor_interface_.init(autoware::motion_utils::PlanningBehavior::ROUTE_OBSTACLE); + + planning_factor_interface_ = std::make_unique( + &node, "dynamic_obstacle_stop"); debug_publisher_ = node.create_publisher("~/" + ns_ + "/debug_markers", 1); @@ -160,15 +162,9 @@ VelocityPlanningResult DynamicObstacleStopModule::plan( debug_data_.stop_pose = stop_pose; if (stop_pose) { result.stop_points.push_back(stop_pose->position); - const auto stop_pose_reached = - planner_data->current_odometry.twist.twist.linear.x < 1e-3 && - autoware::universe_utils::calcDistance2d(ego_data.pose, *stop_pose) < 1e-3; - velocity_factor_interface_.set( - ego_trajectory_points, ego_data.pose, *stop_pose, - stop_pose_reached ? autoware::motion_utils::VelocityFactor::STOPPED - : autoware::motion_utils::VelocityFactor::APPROACHING, - "dynamic_obstacle_stop"); - result.velocity_factor = velocity_factor_interface_.get(); + planning_factor_interface_->add( + ego_trajectory_points, ego_data.pose, *stop_pose, PlanningFactor::STOP, + SafetyFactorArray{}); create_virtual_walls(); } } diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp index 1843d26a22a29..82a6d790bebe7 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.hpp @@ -33,6 +33,7 @@ class DynamicObstacleStopModule : public PluginModuleInterface { public: void init(rclcpp::Node & node, const std::string & module_name) override; + void publish_planning_factor() override { planning_factor_interface_->publish(); }; void update_parameters(const std::vector & parameters) override; VelocityPlanningResult plan( const std::vector & ego_trajectory_points, diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_velocity_limiter_module/src/obstacle_velocity_limiter_module.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_velocity_limiter_module/src/obstacle_velocity_limiter_module.cpp index 1923f023552e3..eb89c027a3b48 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_velocity_limiter_module/src/obstacle_velocity_limiter_module.cpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_obstacle_velocity_limiter_module/src/obstacle_velocity_limiter_module.cpp @@ -48,7 +48,6 @@ void ObstacleVelocityLimiterModule::init(rclcpp::Node & node, const std::string projection_params_ = obstacle_velocity_limiter::ProjectionParameters(node); obstacle_params_ = obstacle_velocity_limiter::ObstacleParameters(node); velocity_params_ = obstacle_velocity_limiter::VelocityParameters(node); - velocity_factor_interface_.init(autoware::motion_utils::PlanningBehavior::ROUTE_OBSTACLE); debug_publisher_ = node.create_publisher("~/" + ns_ + "/debug_markers", 1); diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp index bd85546cb6c56..532cc1e8c7d51 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp @@ -58,7 +58,9 @@ void OutOfLaneModule::init(rclcpp::Node & node, const std::string & module_name) logger_ = node.get_logger(); clock_ = node.get_clock(); init_parameters(node); - velocity_factor_interface_.init(motion_utils::PlanningBehavior::ROUTE_OBSTACLE); + + planning_factor_interface_ = + std::make_unique(&node, "out_of_lane"); debug_publisher_ = node.create_publisher("~/" + ns_ + "/debug_markers", 1); @@ -310,15 +312,9 @@ VelocityPlanningResult OutOfLaneModule::plan( slowdown_pose->position, slowdown_pose->position, slowdown_velocity); } - const auto is_approaching = - motion_utils::calcSignedArcLength( - ego_trajectory_points, ego_data.pose.position, slowdown_pose->position) > 0.1 && - planner_data->current_odometry.twist.twist.linear.x > 0.1; - const auto status = is_approaching ? motion_utils::VelocityFactor::APPROACHING - : motion_utils::VelocityFactor::STOPPED; - velocity_factor_interface_.set( - ego_trajectory_points, ego_data.pose, *slowdown_pose, status, "out_of_lane"); - result.velocity_factor = velocity_factor_interface_.get(); + planning_factor_interface_->add( + ego_trajectory_points, ego_data.pose, *slowdown_pose, PlanningFactor::SLOW_DOWN, + SafetyFactorArray{}); virtual_wall_marker_creator.add_virtual_walls( out_of_lane::debug::create_virtual_walls(*slowdown_pose, slowdown_velocity == 0.0, params_)); virtual_wall_publisher_->publish(virtual_wall_marker_creator.create_markers(clock_->now())); diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.hpp index 72f20f1c63d96..0e73994dd73a7 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.hpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.hpp @@ -38,6 +38,7 @@ class OutOfLaneModule : public PluginModuleInterface { public: void init(rclcpp::Node & node, const std::string & module_name) override; + void publish_planning_factor() override { planning_factor_interface_->publish(); }; void update_parameters(const std::vector & parameters) override; VelocityPlanningResult plan( const std::vector & ego_trajectory_points, diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp index 53860c390b4db..6d683acff667f 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp @@ -18,7 +18,7 @@ #include "planner_data.hpp" #include "velocity_planning_result.hpp" -#include +#include #include #include @@ -32,6 +32,9 @@ namespace autoware::motion_velocity_planner { +using tier4_planning_msgs::msg::PlanningFactor; +using tier4_planning_msgs::msg::SafetyFactorArray; + class PluginModuleInterface { public: @@ -42,7 +45,7 @@ class PluginModuleInterface const std::vector & ego_trajectory_points, const std::shared_ptr planner_data) = 0; virtual std::string get_module_name() const = 0; - autoware::motion_utils::VelocityFactorInterface velocity_factor_interface_; + virtual void publish_planning_factor() {} rclcpp::Logger logger_ = rclcpp::get_logger(""); rclcpp::Publisher::SharedPtr debug_publisher_; rclcpp::Publisher::SharedPtr virtual_wall_publisher_; @@ -50,6 +53,9 @@ class PluginModuleInterface rclcpp::Publisher::SharedPtr processing_time_publisher_; autoware::motion_utils::VirtualWallMarkerCreator virtual_wall_marker_creator{}; + +protected: + std::unique_ptr planning_factor_interface_; }; } // namespace autoware::motion_velocity_planner diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/velocity_planning_result.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/velocity_planning_result.hpp index 1288884a37979..7b41bf0ee9e3e 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/velocity_planning_result.hpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/velocity_planning_result.hpp @@ -17,7 +17,6 @@ #include -#include #include #include @@ -43,7 +42,6 @@ struct VelocityPlanningResult { std::vector stop_points{}; std::vector slowdown_intervals{}; - std::optional velocity_factor{}; }; } // namespace autoware::motion_velocity_planner diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/README.md b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/README.md index 01062f81e77a2..c65593497b8d5 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/README.md +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/README.md @@ -30,10 +30,10 @@ This means that to stop before a wall, a stop point is inserted in the trajector ## Output topics -| Name | Type | Description | -| --------------------------- | ------------------------------------------------- | -------------------------------------------------- | -| `~/output/trajectory` | autoware_planning_msgs::msg::Trajectory | Ego trajectory with updated velocity profile | -| `~/output/velocity_factors` | autoware_adapi_v1_msgs::msg::VelocityFactorsArray | factors causing change in the ego velocity profile | +| Name | Type | Description | +| ----------------------------------------- | ---------------------------------------------- | -------------------------------------------------- | +| `~/output/trajectory` | autoware_planning_msgs::msg::Trajectory | Ego trajectory with updated velocity profile | +| `~/output/planning_factors/` | tier4_planning_msgs::msg::PlanningFactorsArray | factors causing change in the ego velocity profile | ## Services diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.cpp index a78ab1489e080..8f5aa761573b7 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.cpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.cpp @@ -82,9 +82,6 @@ MotionVelocityPlannerNode::MotionVelocityPlannerNode(const rclcpp::NodeOptions & // Publishers trajectory_pub_ = this->create_publisher("~/output/trajectory", 1); - velocity_factor_publisher_ = - this->create_publisher( - "~/output/velocity_factors", 1); processing_time_publisher_ = this->create_publisher( "~/debug/processing_time_ms", 1); @@ -422,20 +419,13 @@ autoware_planning_msgs::msg::Trajectory MotionVelocityPlannerNode::generate_traj resampled_trajectory, std::make_shared(planner_data_)); processing_times["plan_velocities"] = stop_watch.toc("plan_velocities"); - autoware_adapi_v1_msgs::msg::VelocityFactorArray velocity_factors; - velocity_factors.header.frame_id = "map"; - velocity_factors.header.stamp = get_clock()->now(); - for (const auto & planning_result : planning_results) { for (const auto & stop_point : planning_result.stop_points) insert_stop(output_trajectory_msg, stop_point); for (const auto & slowdown_interval : planning_result.slowdown_intervals) insert_slowdown(output_trajectory_msg, slowdown_interval); - if (planning_result.velocity_factor) - velocity_factors.factors.push_back(*planning_result.velocity_factor); } - velocity_factor_publisher_->publish(velocity_factors); return output_trajectory_msg; } diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.hpp index 18d41f5d7fe5d..4235971e76fca 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.hpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/node.hpp @@ -93,8 +93,6 @@ class MotionVelocityPlannerNode : public rclcpp::Node // publishers rclcpp::Publisher::SharedPtr trajectory_pub_; rclcpp::Publisher::SharedPtr debug_viz_pub_; - rclcpp::Publisher::SharedPtr - velocity_factor_publisher_; autoware::universe_utils::ProcessingTimePublisher processing_diag_publisher_{ this, "~/debug/processing_time_ms_diag"}; rclcpp::Publisher::SharedPtr diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/planner_manager.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/planner_manager.cpp index b08798cbef772..5bdf386479283 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/planner_manager.cpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/src/planner_manager.cpp @@ -102,6 +102,8 @@ std::vector MotionVelocityPlannerManager::plan_velocitie VelocityPlanningResult res = plugin->plan(ego_trajectory_points, planner_data); results.push_back(res); + plugin->publish_planning_factor(); + if (res.stop_points.size() > 0) { const auto stop_decision_metric = make_decision_metric(plugin->get_module_name(), "stop"); metrics_.push_back(stop_decision_metric); diff --git a/system/autoware_default_adapi/package.xml b/system/autoware_default_adapi/package.xml index a24d0c8a30b62..e0d3fc0f9e21b 100644 --- a/system/autoware_default_adapi/package.xml +++ b/system/autoware_default_adapi/package.xml @@ -32,6 +32,7 @@ std_srvs tier4_api_msgs tier4_control_msgs + tier4_planning_msgs tier4_system_msgs python3-flask diff --git a/system/autoware_default_adapi/src/planning.cpp b/system/autoware_default_adapi/src/planning.cpp index d89ef6c221666..e11b01115caad 100644 --- a/system/autoware_default_adapi/src/planning.cpp +++ b/system/autoware_default_adapi/src/planning.cpp @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -25,6 +26,34 @@ namespace autoware::default_adapi { +const std::map direction_map = { + {PlanningFactor::SHIFT_RIGHT, SteeringFactor::RIGHT}, + {PlanningFactor::SHIFT_LEFT, SteeringFactor::LEFT}, + {PlanningFactor::TURN_RIGHT, SteeringFactor::RIGHT}, + {PlanningFactor::TURN_LEFT, SteeringFactor::LEFT}}; + +const std::map conversion_map = { + {"behavior_path_planner", PlanningBehavior::INTERSECTION}, + {"static_obstacle_avoidance", PlanningBehavior::AVOIDANCE}, + {"crosswalk", PlanningBehavior::CROSSWALK}, + {"goal_planner", PlanningBehavior::GOAL_PLANNER}, + {"intersection", PlanningBehavior::INTERSECTION}, + {"lane_change_left", PlanningBehavior::LANE_CHANGE}, + {"lane_change_right", PlanningBehavior::LANE_CHANGE}, + {"merge_from_private", PlanningBehavior::MERGE}, + {"no_stopping_area", PlanningBehavior::NO_STOPPING_AREA}, + {"blind_spot", PlanningBehavior::REAR_CHECK}, + {"obstacle_cruise_planner", PlanningBehavior::ROUTE_OBSTACLE}, + {"motion_velocity_planner", PlanningBehavior::ROUTE_OBSTACLE}, + {"walkway", PlanningBehavior::SIDEWALK}, + {"start_planner", PlanningBehavior::START_PLANNER}, + {"stop_line", PlanningBehavior::STOP_SIGN}, + {"surround_obstacle_checker", PlanningBehavior::SURROUNDING_OBSTACLE}, + {"traffic_light", PlanningBehavior::TRAFFIC_SIGNAL}, + {"detection_area", PlanningBehavior::USER_DEFINED_DETECTION_AREA}, + {"virtual_traffic_light", PlanningBehavior::VIRTUAL_TRAFFIC_LIGHT}, + {"run_out", PlanningBehavior::RUN_OUT}}; + template void concat(std::vector & v1, const std::vector & v2) { @@ -49,16 +78,122 @@ std::vector::SharedPtr> init_factors( } template -T merge_factors(const rclcpp::Time stamp, const std::vector & factors) +std::vector convert([[maybe_unused]] const std::vector & factors) +{ + static_assert(sizeof(T) == 0, "Only specializations of convert can be used."); + throw std::logic_error("Only specializations of convert can be used."); +} + +template <> +std::vector convert(const std::vector & factors) +{ + std::vector velocity_factors; + + for (const auto & factor : factors) { + if (factor.behavior != PlanningFactor::SLOW_DOWN && factor.behavior != PlanningFactor::STOP) { + continue; + } + + if (factor.control_points.empty()) { + continue; + } + + if (conversion_map.count(factor.module) == 0) { + continue; + } + + VelocityFactor velocity_factor; + velocity_factor.behavior = conversion_map.at(factor.module); + velocity_factor.pose = factor.control_points.front().pose; + velocity_factor.distance = factor.control_points.front().distance; + + velocity_factors.push_back(velocity_factor); + } + + return velocity_factors; +} + +template <> +std::vector convert(const std::vector & factors) { - T message; + std::vector steering_factors; + + for (const auto & factor : factors) { + if ( + factor.behavior != PlanningFactor::SHIFT_RIGHT && + factor.behavior != PlanningFactor::SHIFT_LEFT && + factor.behavior != PlanningFactor::TURN_RIGHT && + factor.behavior != PlanningFactor::TURN_LEFT) { + continue; + } + + if (factor.control_points.size() < 2) { + continue; + } + + if (conversion_map.count(factor.module) == 0) { + continue; + } + + if (direction_map.count(factor.behavior) == 0) { + continue; + } + + SteeringFactor steering_factor; + steering_factor.behavior = conversion_map.at(factor.module); + steering_factor.direction = direction_map.at(factor.behavior); + steering_factor.pose = std::array{ + factor.control_points.front().pose, factor.control_points.back().pose}; + steering_factor.distance = std::array{ + factor.control_points.front().distance, factor.control_points.back().distance}; + + steering_factors.push_back(steering_factor); + } + + return steering_factors; +} + +template +T merge_factors( + [[maybe_unused]] const rclcpp::Time stamp, + [[maybe_unused]] const std::vector & factors) +{ + static_assert(sizeof(T) == 0, "Only specializations of merge_factors can be used."); + throw std::logic_error("Only specializations of merge_factors can be used."); +} + +template <> +VelocityFactorArray merge_factors( + const rclcpp::Time stamp, const std::vector & factors) +{ + VelocityFactorArray message; message.header.stamp = stamp; message.header.frame_id = "map"; for (const auto & factor : factors) { - if (factor) { - concat(message.factors, factor->factors); + if (!factor) { + continue; } + + concat(message.factors, convert(factor->factors)); + } + return message; +} + +template <> +SteeringFactorArray merge_factors( + const rclcpp::Time stamp, const std::vector & factors) +{ + SteeringFactorArray message; + message.header.stamp = stamp; + message.header.frame_id = "map"; + + for (const auto & factor : factors) { + if (!factor) { + continue; + } + + concat(message.factors, convert(factor->factors)); } return message; } @@ -70,46 +205,33 @@ PlanningNode::PlanningNode(const rclcpp::NodeOptions & options) : Node("planning stop_duration_ = declare_parameter("stop_duration", 1.0); stop_checker_ = std::make_unique(this, stop_duration_ + 1.0); - std::vector velocity_factor_topics = { - "/planning/velocity_factors/blind_spot", - "/planning/velocity_factors/crosswalk", - "/planning/velocity_factors/detection_area", - "/planning/velocity_factors/dynamic_obstacle_stop", - "/planning/velocity_factors/intersection", - "/planning/velocity_factors/merge_from_private", - "/planning/velocity_factors/no_stopping_area", - "/planning/velocity_factors/obstacle_stop", - "/planning/velocity_factors/obstacle_cruise", - "/planning/velocity_factors/occlusion_spot", - "/planning/velocity_factors/run_out", - "/planning/velocity_factors/stop_line", - "/planning/velocity_factors/surround_obstacle", - "/planning/velocity_factors/traffic_light", - "/planning/velocity_factors/virtual_traffic_light", - "/planning/velocity_factors/walkway", - "/planning/velocity_factors/motion_velocity_planner", - "/planning/velocity_factors/static_obstacle_avoidance", - "/planning/velocity_factors/dynamic_obstacle_avoidance", - "/planning/velocity_factors/avoidance_by_lane_change", - "/planning/velocity_factors/lane_change_left", - "/planning/velocity_factors/lane_change_right", - "/planning/velocity_factors/start_planner", - "/planning/velocity_factors/goal_planner"}; - - std::vector steering_factor_topics = { - "/planning/steering_factor/static_obstacle_avoidance", - "/planning/steering_factor/dynamic_obstacle_avoidance", - "/planning/steering_factor/avoidance_by_lane_change", - "/planning/steering_factor/intersection", - "/planning/steering_factor/lane_change_left", - "/planning/steering_factor/lane_change_right", - "/planning/steering_factor/start_planner", - "/planning/steering_factor/goal_planner"}; - - sub_velocity_factors_ = - init_factors(this, velocity_factors_, velocity_factor_topics); - sub_steering_factors_ = - init_factors(this, steering_factors_, steering_factor_topics); + std::vector factor_topics = { + "/planning/planning_factors/behavior_path_planner", + "/planning/planning_factors/blind_spot", + "/planning/planning_factors/crosswalk", + "/planning/planning_factors/detection_area", + "/planning/planning_factors/dynamic_obstacle_stop", + "/planning/planning_factors/intersection", + "/planning/planning_factors/merge_from_private", + "/planning/planning_factors/no_stopping_area", + "/planning/planning_factors/obstacle_cruise_planner", + "/planning/planning_factors/occlusion_spot", + "/planning/planning_factors/run_out", + "/planning/planning_factors/stop_line", + "/planning/planning_factors/surround_obstacle_checker", + "/planning/planning_factors/traffic_light", + "/planning/planning_factors/virtual_traffic_light", + "/planning/planning_factors/walkway", + "/planning/planning_factors/motion_velocity_planner", + "/planning/planning_factors/static_obstacle_avoidance", + "/planning/planning_factors/dynamic_obstacle_avoidance", + "/planning/planning_factors/avoidance_by_lane_change", + "/planning/planning_factors/lane_change_left", + "/planning/planning_factors/lane_change_right", + "/planning/planning_factors/start_planner", + "/planning/planning_factors/goal_planner"}; + + sub_factors_ = init_factors(this, factors_, factor_topics); const auto adaptor = autoware::component_interface_utils::NodeAdaptor(this); adaptor.init_pub(pub_velocity_factors_); @@ -139,8 +261,8 @@ void PlanningNode::on_kinematic_state(const KinematicState::ConstSharedPtr msg) void PlanningNode::on_timer() { using autoware_adapi_v1_msgs::msg::VelocityFactor; - auto velocity = merge_factors(now(), velocity_factors_); - auto steering = merge_factors(now(), steering_factors_); + auto velocity = merge_factors(now(), factors_); + auto steering = merge_factors(now(), factors_); // Set the distance if it is nan. if (trajectory_ && kinematic_state_) { @@ -164,6 +286,13 @@ void PlanningNode::on_timer() } } + for (auto & factor : steering.factors) { + if ((factor.status == SteeringFactor::UNKNOWN) && (!std::isnan(factor.distance.front()))) { + const auto is_turning = factor.distance.front() < 0.0; + factor.status = is_turning ? SteeringFactor::TURNING : SteeringFactor::APPROACHING; + } + } + pub_velocity_factors_->publish(velocity); pub_steering_factors_->publish(steering); } diff --git a/system/autoware_default_adapi/src/planning.hpp b/system/autoware_default_adapi/src/planning.hpp index 3a9b99e33a997..49584475734f6 100644 --- a/system/autoware_default_adapi/src/planning.hpp +++ b/system/autoware_default_adapi/src/planning.hpp @@ -21,7 +21,11 @@ #include #include +#include +#include + #include +#include #include // This file should be included after messages. @@ -30,22 +34,26 @@ namespace autoware::default_adapi { +using autoware_adapi_v1_msgs::msg::PlanningBehavior; +using autoware_adapi_v1_msgs::msg::SteeringFactor; +using autoware_adapi_v1_msgs::msg::SteeringFactorArray; +using autoware_adapi_v1_msgs::msg::VelocityFactor; +using autoware_adapi_v1_msgs::msg::VelocityFactorArray; +using tier4_planning_msgs::msg::PlanningFactor; +using tier4_planning_msgs::msg::PlanningFactorArray; + class PlanningNode : public rclcpp::Node { public: explicit PlanningNode(const rclcpp::NodeOptions & options); private: - using VelocityFactorArray = autoware_adapi_v1_msgs::msg::VelocityFactorArray; - using SteeringFactorArray = autoware_adapi_v1_msgs::msg::SteeringFactorArray; Pub pub_velocity_factors_; Pub pub_steering_factors_; Sub sub_trajectory_; Sub sub_kinematic_state_; - std::vector::SharedPtr> sub_velocity_factors_; - std::vector::SharedPtr> sub_steering_factors_; - std::vector velocity_factors_; - std::vector steering_factors_; + std::vector::SharedPtr> sub_factors_; + std::vector factors_; rclcpp::TimerBase::SharedPtr timer_; using VehicleStopChecker = autoware::motion_utils::VehicleStopCheckerBase; From dd632fc2a2bec57796ea1c0bfbfa9b7dafc93749 Mon Sep 17 00:00:00 2001 From: Mamoru Sobue Date: Thu, 16 Jan 2025 22:45:07 +0900 Subject: [PATCH 47/61] feat(motion_utils): add detail and pass type to VirtualWall (#9940) Signed-off-by: Mamoru Sobue --- .../motion_utils/marker/marker_helper.hpp | 5 ++ .../marker/virtual_wall_marker_creator.hpp | 3 +- .../src/marker/marker_helper.cpp | 49 ++++++++++++++++++- .../marker/virtual_wall_marker_creator.cpp | 10 +++- 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/common/autoware_motion_utils/include/autoware/motion_utils/marker/marker_helper.hpp b/common/autoware_motion_utils/include/autoware/motion_utils/marker/marker_helper.hpp index ee642c93a378f..2b89fc19d1878 100644 --- a/common/autoware_motion_utils/include/autoware/motion_utils/marker/marker_helper.hpp +++ b/common/autoware_motion_utils/include/autoware/motion_utils/marker/marker_helper.hpp @@ -40,6 +40,11 @@ visualization_msgs::msg::MarkerArray createDeadLineVirtualWallMarker( const double longitudinal_offset = 0.0, const std::string & ns_prefix = "", const bool is_driving_forward = true); +visualization_msgs::msg::MarkerArray createIntendedPassVirtualMarker( + const geometry_msgs::msg::Pose & pose, const std::string & module_name, const rclcpp::Time & now, + const int32_t id, const double longitudinal_offset, const std::string & ns_prefix, + const bool is_driving_forward); + visualization_msgs::msg::MarkerArray createDeletedStopVirtualWallMarker( const rclcpp::Time & now, const int32_t id); diff --git a/common/autoware_motion_utils/include/autoware/motion_utils/marker/virtual_wall_marker_creator.hpp b/common/autoware_motion_utils/include/autoware/motion_utils/marker/virtual_wall_marker_creator.hpp index 07fcbd9840c88..fd86c54d65be9 100644 --- a/common/autoware_motion_utils/include/autoware/motion_utils/marker/virtual_wall_marker_creator.hpp +++ b/common/autoware_motion_utils/include/autoware/motion_utils/marker/virtual_wall_marker_creator.hpp @@ -29,12 +29,13 @@ namespace autoware::motion_utils { /// @brief type of virtual wall associated with different marker styles and namespace -enum VirtualWallType { stop, slowdown, deadline }; +enum VirtualWallType { stop, slowdown, deadline, pass }; /// @brief virtual wall to be visualized in rviz struct VirtualWall { geometry_msgs::msg::Pose pose{}; std::string text{}; + std::string detail{}; std::string ns{}; VirtualWallType style = stop; double longitudinal_offset{}; diff --git a/common/autoware_motion_utils/src/marker/marker_helper.cpp b/common/autoware_motion_utils/src/marker/marker_helper.cpp index 91ad1c41eecc3..44b621a53c5f1 100644 --- a/common/autoware_motion_utils/src/marker/marker_helper.cpp +++ b/common/autoware_motion_utils/src/marker/marker_helper.cpp @@ -54,7 +54,7 @@ inline visualization_msgs::msg::MarkerArray createVirtualWallMarkerArray( { auto marker = createDefaultMarker( "map", now, ns_prefix + "factor_text", id, visualization_msgs::msg::Marker::TEXT_VIEW_FACING, - createMarkerScale(0.0, 0.0, 1.0), createMarkerColor(1.0, 1.0, 1.0, 1.0)); + createMarkerScale(0.0, 0.0, 1.0 /*font size*/), createMarkerColor(1.0, 1.0, 1.0, 1.0)); marker.pose = vehicle_front_pose; marker.pose.position.z += 2.0; @@ -85,6 +85,41 @@ inline visualization_msgs::msg::MarkerArray createDeletedVirtualWallMarkerArray( return marker_array; } + +inline visualization_msgs::msg::MarkerArray createIntendedPassArrowMarkerArray( + const geometry_msgs::msg::Pose & vehicle_front_pose, const std::string & module_name, + const std::string & ns_prefix, const rclcpp::Time & now, const int32_t id, + const std_msgs::msg::ColorRGBA & color) +{ + visualization_msgs::msg::MarkerArray marker_array; + + // Arrow + { + auto marker = createDefaultMarker( + "map", now, ns_prefix + "direction", id, visualization_msgs::msg::Marker::ARROW, + createMarkerScale(2.5 /*length*/, 0.15 /*width*/, 1.0 /*height*/), color); + + marker.pose = vehicle_front_pose; + + marker_array.markers.push_back(marker); + } + + // Factor Text + { + auto marker = createDefaultMarker( + "map", now, ns_prefix + "factor_text", id, visualization_msgs::msg::Marker::TEXT_VIEW_FACING, + createMarkerScale(0.0, 0.0, 0.4 /*font size*/), createMarkerColor(1.0, 1.0, 1.0, 1.0)); + + marker.pose = vehicle_front_pose; + marker.pose.position.z += 2.0; + marker.text = module_name; + + marker_array.markers.push_back(marker); + } + + return marker_array; +} + } // namespace namespace autoware::motion_utils @@ -125,6 +160,18 @@ visualization_msgs::msg::MarkerArray createDeadLineVirtualWallMarker( createMarkerColor(0.0, 1.0, 0.0, 0.5)); } +visualization_msgs::msg::MarkerArray createIntendedPassVirtualMarker( + const geometry_msgs::msg::Pose & pose, const std::string & module_name, const rclcpp::Time & now, + const int32_t id, const double longitudinal_offset, const std::string & ns_prefix, + const bool is_driving_forward) +{ + const auto pose_with_offset = autoware::universe_utils::calcOffsetPose( + pose, longitudinal_offset * (is_driving_forward ? 1.0 : -1.0), 0.0, 0.0); + return createIntendedPassArrowMarkerArray( + pose_with_offset, module_name, ns_prefix + "intended_pass_", now, id, + createMarkerColor(0.77, 0.77, 0.77, 0.5)); +} + visualization_msgs::msg::MarkerArray createDeletedStopVirtualWallMarker( const rclcpp::Time & now, const int32_t id) { diff --git a/common/autoware_motion_utils/src/marker/virtual_wall_marker_creator.cpp b/common/autoware_motion_utils/src/marker/virtual_wall_marker_creator.cpp index 4fecaea1bb838..fb8708b5b7baa 100644 --- a/common/autoware_motion_utils/src/marker/virtual_wall_marker_creator.cpp +++ b/common/autoware_motion_utils/src/marker/virtual_wall_marker_creator.cpp @@ -63,10 +63,16 @@ visualization_msgs::msg::MarkerArray VirtualWallMarkerCreator::create_markers( case deadline: create_fn = autoware::motion_utils::createDeadLineVirtualWallMarker; break; + case pass: + create_fn = autoware::motion_utils::createIntendedPassVirtualMarker; + break; } + const auto wall_text = virtual_wall.detail.empty() + ? virtual_wall.text + : virtual_wall.text + "(" + virtual_wall.detail + ")"; auto markers = create_fn( - virtual_wall.pose, virtual_wall.text, now, 0, virtual_wall.longitudinal_offset, - virtual_wall.ns, virtual_wall.is_driving_forward); + virtual_wall.pose, wall_text, now, 0, virtual_wall.longitudinal_offset, virtual_wall.ns, + virtual_wall.is_driving_forward); for (auto & marker : markers.markers) { marker.id = static_cast(marker_count_per_namespace_[marker.ns].current++); marker_array.markers.push_back(marker); From 62e07a18c6c54f3a0213bceae320bb9e56e8af2a Mon Sep 17 00:00:00 2001 From: Kyoichi Sugahara <32741405+kyoichi-sugahara@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:12:30 +0900 Subject: [PATCH 48/61] fix(start_planner, goal_planner): refactor lane departure checker initialization (#9944) --- .../src/pull_over_planner/geometric_pull_over.cpp | 8 ++++++-- .../src/pull_over_planner/shift_pull_over.cpp | 8 ++++++-- .../src/geometric_pull_out.cpp | 6 ++++-- .../src/shift_pull_out.cpp | 6 ++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp index 44dca13ccfd66..b7b4ad83de362 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/geometric_pull_over.cpp @@ -29,8 +29,12 @@ GeometricPullOver::GeometricPullOver( rclcpp::Node & node, const GoalPlannerParameters & parameters, const bool is_forward) : PullOverPlannerBase{node, parameters}, parallel_parking_parameters_{parameters.parallel_parking_parameters}, - lane_departure_checker_{ - lane_departure_checker::Param{parameters.lane_departure_check_expansion_margin}, vehicle_info_}, + lane_departure_checker_{[&]() { + auto lane_departure_checker_params = lane_departure_checker::Param{}; + lane_departure_checker_params.footprint_extra_margin = + parameters.lane_departure_check_expansion_margin; + return LaneDepartureChecker{lane_departure_checker_params, vehicle_info_}; + }()}, is_forward_{is_forward}, left_side_parking_{parameters.parking_policy == ParkingPolicy::LEFT_SIDE} { diff --git a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/shift_pull_over.cpp b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/shift_pull_over.cpp index 8350252369cc6..c8e0788e39b6f 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/shift_pull_over.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_goal_planner_module/src/pull_over_planner/shift_pull_over.cpp @@ -32,8 +32,12 @@ namespace autoware::behavior_path_planner { ShiftPullOver::ShiftPullOver(rclcpp::Node & node, const GoalPlannerParameters & parameters) : PullOverPlannerBase{node, parameters}, - lane_departure_checker_{ - lane_departure_checker::Param{parameters.lane_departure_check_expansion_margin}, vehicle_info_}, + lane_departure_checker_{[&]() { + auto lane_departure_checker_params = lane_departure_checker::Param{}; + lane_departure_checker_params.footprint_extra_margin = + parameters.lane_departure_check_expansion_margin; + return LaneDepartureChecker{lane_departure_checker_params, vehicle_info_}; + }()}, left_side_parking_{parameters.parking_policy == ParkingPolicy::LEFT_SIDE} { } diff --git a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/geometric_pull_out.cpp b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/geometric_pull_out.cpp index 69c5c41405932..ed09e0c0a33d6 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/geometric_pull_out.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/geometric_pull_out.cpp @@ -40,10 +40,12 @@ GeometricPullOut::GeometricPullOut( : PullOutPlannerBase{node, parameters, time_keeper}, parallel_parking_parameters_{parameters.parallel_parking_parameters} { + auto lane_departure_checker_params = autoware::lane_departure_checker::Param{}; + lane_departure_checker_params.footprint_extra_margin = + parameters.lane_departure_check_expansion_margin; lane_departure_checker_ = std::make_shared( - autoware::lane_departure_checker::Param{parameters.lane_departure_check_expansion_margin}, - vehicle_info_, time_keeper_); + lane_departure_checker_params, vehicle_info_); planner_.setParameters(parallel_parking_parameters_); } diff --git a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/shift_pull_out.cpp b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/shift_pull_out.cpp index 8f4de1d3636de..16a3d4ffd842a 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/shift_pull_out.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_start_planner_module/src/shift_pull_out.cpp @@ -44,10 +44,12 @@ ShiftPullOut::ShiftPullOut( std::shared_ptr time_keeper) : PullOutPlannerBase{node, parameters, time_keeper} { + autoware::lane_departure_checker::Param lane_departure_checker_params; + lane_departure_checker_params.footprint_extra_margin = + parameters.lane_departure_check_expansion_margin; lane_departure_checker_ = std::make_shared( - autoware::lane_departure_checker::Param{parameters.lane_departure_check_expansion_margin}, - vehicle_info_, time_keeper_); + lane_departure_checker_params, vehicle_info_, time_keeper_); } std::optional ShiftPullOut::plan( From 0bf689c2dc5a39dbe8749f270d5c21ec4733e56a Mon Sep 17 00:00:00 2001 From: Zulfaqar Azmi <93502286+zulfaqar-azmi-t4@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:39:33 +0900 Subject: [PATCH 49/61] refactor(lane_change): add missing safety check parameter (#9928) * refactor(lane_change): parameterize incoming object yaw threshold Signed-off-by: Zulfaqar Azmi * Readme Signed-off-by: Zulfaqar Azmi * Update planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp Co-authored-by: Maxime CLEMENT <78338830+maxime-clem@users.noreply.github.com> * Add missing parameters Signed-off-by: Zulfaqar Azmi * missing dot Signed-off-by: Zulfaqar Azmi * Update planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md Co-authored-by: mkquda <168697710+mkquda@users.noreply.github.com> * update readme Signed-off-by: Zulfaqar Azmi --------- Signed-off-by: Zulfaqar Azmi Co-authored-by: Maxime CLEMENT <78338830+maxime-clem@users.noreply.github.com> Co-authored-by: mkquda <168697710+mkquda@users.noreply.github.com> --- .../README.md | 7 +++- .../config/lane_change.param.yaml | 7 +++- .../structs/parameters.hpp | 1 + .../src/manager.cpp | 32 ++++++++++++++++++- .../src/scene.cpp | 8 +++-- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md index 20fd564049133..601fb893f82c6 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/README.md @@ -1149,7 +1149,8 @@ The following parameters are used to configure terminal lane change path feature | `collision_check.check_other_lanes` | [-] | boolean | If true, the lane change module includes objects in other lanes when performing collision assessment. | false | | `collision_check.use_all_predicted_paths` | [-] | boolean | If false, use only the predicted path that has the maximum confidence. | true | | `collision_check.prediction_time_resolution` | [s] | double | Time resolution for object's path interpolation and collision check. | 0.5 | -| `collision_check.yaw_diff_threshold` | [rad] | double | Maximum yaw difference between ego and object when executing rss-based collision checking | 3.1416 | +| `collision_check.yaw_diff_threshold` | [rad] | double | Maximum yaw difference between predicted ego pose and predicted object pose when executing rss-based collision checking | 3.1416 | +| `collision_check.th_incoming_object_yaw` | [rad] | double | Maximum yaw difference between current ego pose and current object pose. Objects with a yaw difference exceeding this value are excluded from the safety check. | 2.3562 | #### safety constraints during lane change path is computed @@ -1162,6 +1163,7 @@ The following parameters are used to configure terminal lane change path feature | `safety_check.execution.lateral_distance_max_threshold` | [m] | double | The lateral distance threshold that is used to determine whether lateral distance between two object is enough and whether lane change is safe. | 2.0 | | `safety_check.execution.longitudinal_distance_min_threshold` | [m] | double | The longitudinal distance threshold that is used to determine whether longitudinal distance between two object is enough and whether lane change is safe. | 3.0 | | `safety_check.execution.longitudinal_velocity_delta_time` | [m] | double | The time multiplier that is used to compute the actual gap between vehicle at each predicted points (not RSS distance) | 0.8 | +| `safety_check.execution.extended_polygon_policy` | [-] | string | Policy used to determine the polygon shape for the safety check. Available options are: `rectangle` or `along-path`. | `rectangle` | #### safety constraints specifically for stopped or parked vehicles @@ -1174,6 +1176,7 @@ The following parameters are used to configure terminal lane change path feature | `safety_check.parked.lateral_distance_max_threshold` | [m] | double | The lateral distance threshold that is used to determine whether lateral distance between two object is enough and whether lane change is safe. | 1.0 | | `safety_check.parked.longitudinal_distance_min_threshold` | [m] | double | The longitudinal distance threshold that is used to determine whether longitudinal distance between two object is enough and whether lane change is safe. | 3.0 | | `safety_check.parked.longitudinal_velocity_delta_time` | [m] | double | The time multiplier that is used to compute the actual gap between vehicle at each predicted points (not RSS distance) | 0.8 | +| `safety_check.parked.extended_polygon_policy` | [-] | string | Policy used to determine the polygon shape for the safety check. Available options are: `rectangle` or `along-path`. | `rectangle` | ##### safety constraints to cancel lane change path @@ -1186,6 +1189,7 @@ The following parameters are used to configure terminal lane change path feature | `safety_check.cancel.lateral_distance_max_threshold` | [m] | double | The lateral distance threshold that is used to determine whether lateral distance between two object is enough and whether lane change is safe. | 1.0 | | `safety_check.cancel.longitudinal_distance_min_threshold` | [m] | double | The longitudinal distance threshold that is used to determine whether longitudinal distance between two object is enough and whether lane change is safe. | 2.5 | | `safety_check.cancel.longitudinal_velocity_delta_time` | [m] | double | The time multiplier that is used to compute the actual gap between vehicle at each predicted points (not RSS distance) | 0.6 | +| `safety_check.cancel.extended_polygon_policy` | [-] | string | Policy used to determine the polygon shape for the safety check. Available options are: `rectangle` or `along-path`. | `rectangle` | ##### safety constraints used during lane change path is computed when ego is stuck @@ -1198,6 +1202,7 @@ The following parameters are used to configure terminal lane change path feature | `safety_check.stuck.lateral_distance_max_threshold` | [m] | double | The lateral distance threshold that is used to determine whether lateral distance between two object is enough and whether lane change is safe. | 2.0 | | `safety_check.stuck.longitudinal_distance_min_threshold` | [m] | double | The longitudinal distance threshold that is used to determine whether longitudinal distance between two object is enough and whether lane change is safe. | 3.0 | | `safety_check.stuck.longitudinal_velocity_delta_time` | [m] | double | The time multiplier that is used to compute the actual gap between vehicle at each predicted points (not RSS distance) | 0.8 | +| `safety_check.stuck.extended_polygon_policy` | [-] | string | Policy used to determine the polygon shape for the safety check. Available options are: `rectangle` or `along-path`. | `rectangle` | (\*1) the value must be negative. diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml index 15eb23daecf95..71fac1246598f 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/config/lane_change.param.yaml @@ -58,6 +58,7 @@ lateral_distance_max_threshold: 2.0 longitudinal_distance_min_threshold: 3.0 longitudinal_velocity_delta_time: 0.0 + extended_polygon_policy: "rectangle" parked: expected_front_deceleration: -1.0 expected_rear_deceleration: -2.0 @@ -66,6 +67,7 @@ lateral_distance_max_threshold: 1.0 longitudinal_distance_min_threshold: 3.0 longitudinal_velocity_delta_time: 0.0 + extended_polygon_policy: "rectangle" cancel: expected_front_deceleration: -1.0 expected_rear_deceleration: -2.0 @@ -74,6 +76,7 @@ lateral_distance_max_threshold: 1.0 longitudinal_distance_min_threshold: 2.5 longitudinal_velocity_delta_time: 0.0 + extended_polygon_policy: "rectangle" stuck: expected_front_deceleration: -1.0 expected_rear_deceleration: -1.0 @@ -82,6 +85,7 @@ lateral_distance_max_threshold: 2.0 longitudinal_distance_min_threshold: 3.0 longitudinal_velocity_delta_time: 0.0 + extended_polygon_policy: "rectangle" # lane expansion for object filtering lane_expansion: @@ -123,7 +127,8 @@ intersection: true turns: true prediction_time_resolution: 0.5 - yaw_diff_threshold: 3.1416 + th_incoming_object_yaw: 2.3562 # [rad] + yaw_diff_threshold: 3.1416 # [rad] check_current_lanes: false check_other_lanes: false use_all_predicted_paths: false diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp index 60386f535fc64..358f60f3193d5 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/include/autoware/behavior_path_lane_change_module/structs/parameters.hpp @@ -94,6 +94,7 @@ struct CollisionCheckParameters bool check_current_lane{true}; bool check_other_lanes{true}; bool use_all_predicted_paths{false}; + double th_incoming_object_yaw{2.3562}; double th_yaw_diff{3.1416}; double prediction_time_resolution{0.5}; }; diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp index 450497fb2ca29..589338d7b3ace 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/manager.cpp @@ -152,6 +152,8 @@ LCParamPtr LaneChangeModuleManager::set_params(rclcpp::Node * node, const std::s getOrDeclareParameter(*node, parameter("collision_check.prediction_time_resolution")); p.safety.collision_check.th_yaw_diff = getOrDeclareParameter(*node, parameter("collision_check.yaw_diff_threshold")); + p.safety.collision_check.th_incoming_object_yaw = + getOrDeclareParameter(*node, parameter("collision_check.th_incoming_object_yaw")); // rss check auto set_rss_params = [&](auto & params, const std::string & prefix) { @@ -169,6 +171,8 @@ LCParamPtr LaneChangeModuleManager::set_params(rclcpp::Node * node, const std::s *node, parameter(prefix + ".rear_vehicle_safety_time_margin")); params.lateral_distance_max_threshold = getOrDeclareParameter(*node, parameter(prefix + ".lateral_distance_max_threshold")); + params.extended_polygon_policy = + getOrDeclareParameter(*node, parameter(prefix + ".extended_polygon_policy")); }; set_rss_params(p.safety.rss_params, "safety_check.execution"); set_rss_params(p.safety.rss_params_for_parked, "safety_check.parked"); @@ -454,6 +458,19 @@ void LaneChangeModuleManager::updateModuleParams(const std::vectorsafety.collision_check.prediction_time_resolution); updateParam( parameters, ns + "yaw_diff_threshold", p->safety.collision_check.th_yaw_diff); + + auto th_incoming_object_yaw = p->safety.collision_check.th_incoming_object_yaw; + updateParam(parameters, ns + "th_incoming_object_yaw", th_incoming_object_yaw); + if (th_incoming_object_yaw >= M_PI_2) { + p->safety.collision_check.th_incoming_object_yaw = th_incoming_object_yaw; + } else { + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 5000, + "The value of th_incoming_object_yaw (%.3f rad) is less than the minimum possible value " + "(%.3f " + "rad).", + th_incoming_object_yaw, M_PI_2); + } } { @@ -483,7 +500,7 @@ void LaneChangeModuleManager::updateModuleParams(const std::vector(parameters, ns + "stop_time", p->th_stop_time); } - auto update_rss_params = [¶meters](const std::string & prefix, auto & params) { + auto update_rss_params = [¶meters, this](const std::string & prefix, auto & params) { using autoware::universe_utils::updateParam; updateParam( parameters, prefix + "longitudinal_distance_min_threshold", @@ -502,6 +519,19 @@ void LaneChangeModuleManager::updateModuleParams(const std::vector( parameters, prefix + "lateral_distance_max_threshold", params.lateral_distance_max_threshold); + + auto extended_polygon_policy = params.extended_polygon_policy; + updateParam( + parameters, prefix + "extended_polygon_policy", extended_polygon_policy); + if (extended_polygon_policy == "rectangle" || extended_polygon_policy == "along_path") { + params.extended_polygon_policy = extended_polygon_policy; + } else { + RCLCPP_WARN_THROTTLE( + node_->get_logger(), *node_->get_clock(), 1000, + "Policy %s not supported or there's typo. Make sure you choose either 'rectangle' or " + "'along_path'", + extended_polygon_policy.c_str()); + } }; update_rss_params("lane_change.safety_check.execution.", p->safety.rss_params); diff --git a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp index 45fcd6fa99086..611a0b60a4366 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_planner/autoware_behavior_path_lane_change_module/src/scene.cpp @@ -1051,7 +1051,9 @@ void NormalLaneChange::filterOncomingObjects(PredictedObjects & objects) const const auto is_same_direction = [&](const PredictedObject & object) { const auto & object_pose = object.kinematics.initial_pose_with_covariance.pose; - return !utils::path_safety_checker::isTargetObjectOncoming(current_pose, object_pose); + return !utils::path_safety_checker::isTargetObjectOncoming( + current_pose, object_pose, + common_data_ptr_->lc_param_ptr->safety.collision_check.th_incoming_object_yaw); }; // Perception noise could make stationary objects seem opposite the ego vehicle; check the @@ -1792,7 +1794,6 @@ bool NormalLaneChange::is_colliding( constexpr auto is_safe{true}; auto current_debug_data = utils::path_safety_checker::createObjectDebug(obj); - constexpr auto collision_check_yaw_diff_threshold{M_PI}; constexpr auto hysteresis_factor{1.0}; const auto obj_predicted_paths = utils::path_safety_checker::getPredictedPathFromObj( obj, lane_change_parameters_->safety.collision_check.use_all_predicted_paths); @@ -1817,7 +1818,8 @@ bool NormalLaneChange::is_colliding( const auto collided_polygons = utils::path_safety_checker::get_collided_polygons( lane_change_path.path, ego_predicted_path, obj, predicted_obj_path, bpp_param.vehicle_info, selected_rss_param, hysteresis_factor, safety_check_max_vel, - collision_check_yaw_diff_threshold, current_debug_data.second); + common_data_ptr_->lc_param_ptr->safety.collision_check.th_yaw_diff, + current_debug_data.second); if (collided_polygons.empty()) { utils::path_safety_checker::updateCollisionCheckDebugMap( From 67ab350f6e1af0c14bee74d6913c99165c2e9262 Mon Sep 17 00:00:00 2001 From: Mamoru Sobue Date: Fri, 17 Jan 2025 00:05:32 +0900 Subject: [PATCH 50/61] feat(behavior_velocity_planner)!: remove velocity_factor completely (#9943) * feat(behavior_velocity_planner)!: remove velocity_factor completely Signed-off-by: Mamoru Sobue * minimize diff Signed-off-by: Mamoru Sobue --------- Signed-off-by: Mamoru Sobue --- .../src/scene.cpp | 8 +++--- .../src/scene_intersection.cpp | 2 -- .../src/scene.cpp | 19 +++++++++----- .../src/scene_no_stopping_area.cpp | 9 ++++--- .../src/scene_occlusion_spot.cpp | 2 -- .../scene_module_interface.hpp | 22 ---------------- .../src/scene.cpp | 26 +++++-------------- .../src/scene.hpp | 5 ---- .../src/manager.cpp | 12 --------- .../src/scene.cpp | 7 ++--- .../src/scene.cpp | 15 ++++++----- .../src/scene.hpp | 4 --- 12 files changed, 39 insertions(+), 92 deletions(-) diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp index 59f6f20937f41..7e6a320f3ddad 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp @@ -46,7 +46,6 @@ DetectionAreaModule::DetectionAreaModule( planner_param_(planner_param), debug_data_() { - velocity_factor_.init(PlanningBehavior::USER_DEFINED_DETECTION_AREA); } bool DetectionAreaModule::modifyPathVelocity(PathWithLaneId * path) @@ -180,9 +179,10 @@ bool DetectionAreaModule::modifyPathVelocity(PathWithLaneId * path) // Create StopReason { - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_point->second, - VelocityFactor::UNKNOWN); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); } return true; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp index 2d5da0f070ed9..5b8aca1c8ec9d 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp @@ -44,8 +44,6 @@ namespace autoware::behavior_velocity_planner { namespace bg = boost::geometry; -using autoware::motion_utils::VelocityFactorInterface; - IntersectionModule::IntersectionModule( const int64_t module_id, const int64_t lane_id, [[maybe_unused]] std::shared_ptr planner_data, diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp index f32210bc502bf..0e646e92035cf 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp @@ -38,7 +38,6 @@ NoDrivableLaneModule::NoDrivableLaneModule( debug_data_(), state_(State::INIT) { - velocity_factor_.init(PlanningBehavior::NO_DRIVABLE_LANE); } bool NoDrivableLaneModule::modifyPathVelocity(PathWithLaneId * path) @@ -166,8 +165,10 @@ void NoDrivableLaneModule::handle_approaching_state(PathWithLaneId * path) // Get stop point and stop factor { const auto & stop_pose = op_stop_pose.value(); - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::APPROACHING); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); const auto virtual_wall_pose = autoware::motion_utils::calcLongitudinalOffsetPose( path->points, stop_pose.position, debug_data_.base_link2front); @@ -214,8 +215,10 @@ void NoDrivableLaneModule::handle_inside_no_drivable_lane_state(PathWithLaneId * // Get stop point and stop factor { const auto & stop_pose = autoware::universe_utils::getPose(path->points.at(0)); - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::APPROACHING); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); const auto & virtual_wall_pose = autoware::motion_utils::calcLongitudinalOffsetPose( path->points, stop_pose.position, debug_data_.base_link2front); @@ -252,8 +255,10 @@ void NoDrivableLaneModule::handle_stopped_state(PathWithLaneId * path) // Get stop point and stop factor { const auto & stop_pose = ego_pos_on_path.pose; - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::STOPPED); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); const auto virtual_wall_pose = autoware::motion_utils::calcLongitudinalOffsetPose( path->points, stop_pose.position, debug_data_.base_link2front); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp index bcb8b365f6205..c788a54073ed6 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp @@ -50,7 +50,6 @@ NoStoppingAreaModule::NoStoppingAreaModule( planner_param_(planner_param), debug_data_() { - velocity_factor_.init(PlanningBehavior::NO_STOPPING_AREA); state_machine_.setState(StateMachine::State::GO); state_machine_.setMarginTime(planner_param_.state_clear_time); } @@ -144,9 +143,11 @@ bool NoStoppingAreaModule::modifyPathVelocity(PathWithLaneId * path) // Create StopReason { - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_point->second, - VelocityFactor::UNKNOWN); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_point->second, stop_point->second, + tier4_planning_msgs::msg::PlanningFactor::STOP, + tier4_planning_msgs::msg::SafetyFactorArray{}, true /*is_driving_forward*/, 0.0, + 0.0 /*shift distance*/, ""); } } else if (state_machine_.getState() == StateMachine::State::GO) { diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp index 1163b00e08ccb..fa259b2bea9aa 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp @@ -70,8 +70,6 @@ OcclusionSpotModule::OcclusionSpotModule( : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), param_(planner_param) { - velocity_factor_.init(PlanningBehavior::UNKNOWN); - if (param_.detection_method == utils::DETECTION_METHOD::OCCUPANCY_GRID) { debug_data_.detection_type = "occupancy"; //! occupancy grid limitation( 100 * 100 ) diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp index ad1ae1d47664a..5bff3ca343e72 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -28,8 +27,6 @@ #include #include -#include -#include #include #include #include @@ -51,8 +48,6 @@ namespace autoware::behavior_velocity_planner { -using autoware::motion_utils::PlanningBehavior; -using autoware::motion_utils::VelocityFactor; using autoware::objects_of_interest_marker_interface::ColorName; using autoware::objects_of_interest_marker_interface::ObjectsOfInterestMarkerInterface; using autoware::universe_utils::DebugPublisher; @@ -97,8 +92,6 @@ class SceneModuleInterface planner_data_ = planner_data; } - void resetVelocityFactor() { velocity_factor_.reset(); } - VelocityFactor getVelocityFactor() const { return velocity_factor_.get(); } std::vector getObjectsOfInterestData() const { return objects_of_interest_; } void clearObjectsOfInterestData() { objects_of_interest_.clear(); } @@ -107,7 +100,6 @@ class SceneModuleInterface rclcpp::Logger logger_; rclcpp::Clock::SharedPtr clock_; std::shared_ptr planner_data_; - autoware::motion_utils::VelocityFactorInterface velocity_factor_; // TODO(soblin): remove this std::vector objects_of_interest_; mutable std::shared_ptr time_keeper_; std::shared_ptr planning_factor_interface_; @@ -143,8 +135,6 @@ class SceneModuleManagerInterface } pub_virtual_wall_ = node.create_publisher( std::string("~/virtual_wall/") + module_name, 5); - pub_velocity_factor_ = node.create_publisher( - std::string("/planning/velocity_factors/") + module_name, 1); planning_factor_interface_ = std::make_shared(&node, module_name); @@ -180,21 +170,12 @@ class SceneModuleManagerInterface StopWatch stop_watch; stop_watch.tic("Total"); visualization_msgs::msg::MarkerArray debug_marker_array; - autoware_adapi_v1_msgs::msg::VelocityFactorArray velocity_factor_array; - velocity_factor_array.header.frame_id = "map"; - velocity_factor_array.header.stamp = clock_->now(); for (const auto & scene_module : scene_modules_) { - scene_module->resetVelocityFactor(); scene_module->setPlannerData(planner_data_); scene_module->modifyPathVelocity(path); // The velocity factor must be called after modifyPathVelocity. - // TODO(soblin): remove this - const auto velocity_factor = scene_module->getVelocityFactor(); - if (velocity_factor.behavior != PlanningBehavior::UNKNOWN) { - velocity_factor_array.factors.emplace_back(velocity_factor); - } for (const auto & marker : scene_module->createDebugMarkerArray().markers) { debug_marker_array.markers.push_back(marker); @@ -203,7 +184,6 @@ class SceneModuleManagerInterface virtual_wall_marker_creator_.add_virtual_walls(scene_module->createVirtualWalls()); } - pub_velocity_factor_->publish(velocity_factor_array); planning_factor_interface_->publish(); pub_debug_->publish(debug_marker_array); if (is_publish_debug_path_) { @@ -274,8 +254,6 @@ class SceneModuleManagerInterface rclcpp::Publisher::SharedPtr pub_virtual_wall_; rclcpp::Publisher::SharedPtr pub_debug_; rclcpp::Publisher::SharedPtr pub_debug_path_; - rclcpp::Publisher::SharedPtr - pub_velocity_factor_; std::shared_ptr processing_time_publisher_; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp index 71a5ea3b9e807..e2ddbc75c7b57 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp @@ -38,7 +38,6 @@ StopLineModule::StopLineModule( state_(State::APPROACH), debug_data_() { - velocity_factor_.init(PlanningBehavior::STOP_SIGN); } bool StopLineModule::modifyPathVelocity(PathWithLaneId * path) @@ -62,7 +61,12 @@ bool StopLineModule::modifyPathVelocity(PathWithLaneId * path) path->points = trajectory->restore(); - updateVelocityFactor(&velocity_factor_, state_, *stop_point - ego_s); + // TODO(soblin): PlanningFactorInterface use trajectory class + planning_factor_interface_->add( + path->points, trajectory->compute(*stop_point).point.pose, + planner_data_->current_odometry->pose, planner_data_->current_odometry->pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, "stopline"); updateStateAndStoppedTime( &state_, &stopped_time_, clock_->now(), *stop_point - ego_s, planner_data_->isVehicleStopped()); @@ -152,24 +156,6 @@ void StopLineModule::updateStateAndStoppedTime( } } -void StopLineModule::updateVelocityFactor( - autoware::motion_utils::VelocityFactorInterface * velocity_factor, const State & state, - const double & distance_to_stop_point) -{ - switch (state) { - case State::APPROACH: { - velocity_factor->set(distance_to_stop_point, VelocityFactor::APPROACHING); - break; - } - case State::STOPPED: { - velocity_factor->set(distance_to_stop_point, VelocityFactor::STOPPED); - break; - } - case State::START: - break; - } -} - void StopLineModule::updateDebugData( DebugData * debug_data, const geometry_msgs::msg::Pose & stop_pose, const State & state) const { diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp index aac830b0e9f24..7d430463c18b9 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp @@ -18,7 +18,6 @@ #include "autoware/behavior_velocity_planner_common/scene_module_interface.hpp" #include "autoware/behavior_velocity_planner_common/utilization/util.hpp" -#include "autoware/motion_utils/factor/velocity_factor_interface.hpp" #include "autoware/trajectory/path_point_with_lane_id.hpp" #include @@ -98,10 +97,6 @@ class StopLineModule : public SceneModuleInterface State * state, std::optional * stopped_time, const rclcpp::Time & now, const double & distance_to_stop_point, const bool & is_vehicle_stopped) const; - static void updateVelocityFactor( - autoware::motion_utils::VelocityFactorInterface * velocity_factor, const State & state, - const double & distance_to_stop_point); - void updateDebugData( DebugData * debug_data, const geometry_msgs::msg::Pose & stop_pose, const State & state) const; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp index 9a402f31af0e4..1d1ee7fc996b2 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/manager.cpp @@ -53,24 +53,13 @@ void TrafficLightModuleManager::modifyPathVelocity(tier4_planning_msgs::msg::Pat autoware_perception_msgs::msg::TrafficLightGroup tl_state; - autoware_adapi_v1_msgs::msg::VelocityFactorArray velocity_factor_array; - velocity_factor_array.header.frame_id = "map"; - velocity_factor_array.header.stamp = clock_->now(); - nearest_ref_stop_path_point_index_ = static_cast(path->points.size() - 1); for (const auto & scene_module : scene_modules_) { std::shared_ptr traffic_light_scene_module( std::dynamic_pointer_cast(scene_module)); - traffic_light_scene_module->resetVelocityFactor(); traffic_light_scene_module->setPlannerData(planner_data_); traffic_light_scene_module->modifyPathVelocity(path); - // The velocity factor must be called after modifyPathVelocity. - const auto velocity_factor = traffic_light_scene_module->getVelocityFactor(); - if (velocity_factor.behavior != PlanningBehavior::UNKNOWN) { - velocity_factor_array.factors.emplace_back(velocity_factor); - } - if ( traffic_light_scene_module->getFirstRefStopPathPointIndex() < nearest_ref_stop_path_point_index_) { @@ -88,7 +77,6 @@ void TrafficLightModuleManager::modifyPathVelocity(tier4_planning_msgs::msg::Pat virtual_wall_marker_creator_.add_virtual_walls( traffic_light_scene_module->createVirtualWalls()); } - pub_velocity_factor_->publish(velocity_factor_array); pub_debug_->publish(debug_marker_array); pub_virtual_wall_->publish(virtual_wall_marker_creator_.create_markers(clock_->now())); pub_tl_state_->publish(tl_state); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp index b051d5ff7eb76..becbaf5ee05f2 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp @@ -54,7 +54,6 @@ TrafficLightModule::TrafficLightModule( debug_data_(), is_prev_state_stop_(false) { - velocity_factor_.init(PlanningBehavior::TRAFFIC_SIGNAL); planner_param_ = planner_param; } @@ -293,9 +292,11 @@ tier4_planning_msgs::msg::PathWithLaneId TrafficLightModule::insertStopPose( size_t insert_index = insert_target_point_idx; planning_utils::insertVelocity(modified_path, target_point_with_lane_id, 0.0, insert_index); - velocity_factor_.set( + planning_factor_interface_->add( modified_path.points, planner_data_->current_odometry->pose, - target_point_with_lane_id.point.pose, VelocityFactor::UNKNOWN); + target_point_with_lane_id.point.pose, target_point_with_lane_id.point.pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); return modified_path; } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp index 9ba7b0bccf1b9..a5779cfc0712a 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp @@ -48,8 +48,6 @@ VirtualTrafficLightModule::VirtualTrafficLightModule( lane_(lane), planner_param_(planner_param) { - velocity_factor_.init(PlanningBehavior::VIRTUAL_TRAFFIC_LIGHT); - // Get map data const auto instrument = reg_elem_.getVirtualTrafficLight(); const auto instrument_bottom_line = toAutowarePoints(instrument); @@ -420,9 +418,10 @@ void VirtualTrafficLightModule::insertStopVelocityAtStopLine( } // Set StopReason - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::UNKNOWN, - command_.type); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); // Set data for visualization module_data_.stop_head_pose_at_stop_line = @@ -453,8 +452,10 @@ void VirtualTrafficLightModule::insertStopVelocityAtEndLine( } // Set StopReason - velocity_factor_.set( - path->points, planner_data_->current_odometry->pose, stop_pose, VelocityFactor::UNKNOWN); + planning_factor_interface_->add( + path->points, planner_data_->current_odometry->pose, stop_pose, stop_pose, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); // Set data for visualization module_data_.stop_head_pose_at_end_line = diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp index 9e7a1192d9869..0661267b3d361 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp @@ -113,10 +113,6 @@ class VirtualTrafficLightModule : public SceneModuleInterface void updateInfrastructureCommand(); - void setVelocityFactor( - const geometry_msgs::msg::Pose & stop_pose, - autoware_adapi_v1_msgs::msg::VelocityFactor * velocity_factor); - std::optional getPathIndexOfFirstEndLine(); bool isBeforeStartLine(const size_t end_line_idx); From 08dd641f5ab051eba69d68329cc6c1c6d752de98 Mon Sep 17 00:00:00 2001 From: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:15:18 +0900 Subject: [PATCH 51/61] fix(obstacle_stop_planner): migrate planning factor (#9939) * fix(obstacle_stop_planner): migrate planning factor Signed-off-by: satoshi-ota * fix(autoware_default_adapi): add coversion map Signed-off-by: satoshi-ota --------- Signed-off-by: satoshi-ota --- .../src/debug_marker.cpp | 35 ++++++------------- .../src/debug_marker.hpp | 10 ++---- .../autoware_default_adapi/src/planning.cpp | 2 ++ 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp b/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp index 93526518306af..62b9ae124f555 100644 --- a/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp +++ b/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp @@ -45,12 +45,13 @@ namespace autoware::motion_planning { ObstacleStopPlannerDebugNode::ObstacleStopPlannerDebugNode( rclcpp::Node * node, const double base_link2front) -: node_(node), base_link2front_(base_link2front) +: node_(node), + base_link2front_(base_link2front), + planning_factor_interface_{std::make_unique( + node, "obstacle_stop_planner")} { virtual_wall_pub_ = node_->create_publisher("~/virtual_wall", 1); debug_viz_pub_ = node_->create_publisher("~/debug/marker", 1); - velocity_factor_pub_ = - node_->create_publisher("/planning/velocity_factors/obstacle_stop", 1); pub_debug_values_ = node_->create_publisher("~/obstacle_stop/debug_values", 1); } @@ -189,8 +190,13 @@ void ObstacleStopPlannerDebugNode::publish() debug_viz_pub_->publish(visualization_msg); /* publish stop reason for autoware api */ - const auto velocity_factor_msg = makeVelocityFactorArray(); - velocity_factor_pub_->publish(velocity_factor_msg); + if (stop_pose_ptr_) { + planning_factor_interface_->add( + std::numeric_limits::quiet_NaN(), *stop_pose_ptr_, + tier4_planning_msgs::msg::PlanningFactor::STOP, tier4_planning_msgs::msg::SafetyFactorArray{}, + true /*is_driving_forward*/, 0.0, 0.0 /*shift distance*/, ""); + } + planning_factor_interface_->publish(); // publish debug values Float32MultiArrayStamped debug_msg{}; @@ -492,23 +498,4 @@ MarkerArray ObstacleStopPlannerDebugNode::makeVisualizationMarker() return msg; } -VelocityFactorArray ObstacleStopPlannerDebugNode::makeVelocityFactorArray() -{ - VelocityFactorArray velocity_factor_array; - velocity_factor_array.header.frame_id = "map"; - velocity_factor_array.header.stamp = node_->now(); - - if (stop_pose_ptr_) { - using distance_type = VelocityFactor::_distance_type; - VelocityFactor velocity_factor; - velocity_factor.behavior = PlanningBehavior::ROUTE_OBSTACLE; - velocity_factor.pose = *stop_pose_ptr_; - velocity_factor.distance = std::numeric_limits::quiet_NaN(); - velocity_factor.status = VelocityFactor::UNKNOWN; - velocity_factor.detail = std::string(); - velocity_factor_array.factors.push_back(velocity_factor); - } - return velocity_factor_array; -} - } // namespace autoware::motion_planning diff --git a/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp b/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp index d13e775e3d683..dd9e5e3af1b3d 100644 --- a/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp +++ b/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp @@ -14,10 +14,9 @@ #ifndef DEBUG_MARKER_HPP_ #define DEBUG_MARKER_HPP_ +#include #include -#include -#include #include #include #include @@ -42,9 +41,6 @@ using std_msgs::msg::Header; using visualization_msgs::msg::Marker; using visualization_msgs::msg::MarkerArray; -using autoware_adapi_v1_msgs::msg::PlanningBehavior; -using autoware_adapi_v1_msgs::msg::VelocityFactor; -using autoware_adapi_v1_msgs::msg::VelocityFactorArray; using tier4_debug_msgs::msg::Float32MultiArrayStamped; enum class PolygonType : int8_t { Vehicle = 0, Collision, SlowDownRange, SlowDown, Obstacle }; @@ -109,7 +105,6 @@ class ObstacleStopPlannerDebugNode bool pushObstaclePoint(const pcl::PointXYZ & obstacle_point, const PointType & type); MarkerArray makeVirtualWallMarker(); MarkerArray makeVisualizationMarker(); - VelocityFactorArray makeVelocityFactorArray(); void setDebugValues(const DebugValues::TYPE type, const double val) { @@ -120,11 +115,12 @@ class ObstacleStopPlannerDebugNode private: rclcpp::Publisher::SharedPtr virtual_wall_pub_; rclcpp::Publisher::SharedPtr debug_viz_pub_; - rclcpp::Publisher::SharedPtr velocity_factor_pub_; rclcpp::Publisher::SharedPtr pub_debug_values_; rclcpp::Node * node_; double base_link2front_; + std::unique_ptr planning_factor_interface_; + std::shared_ptr stop_pose_ptr_; std::shared_ptr target_stop_pose_ptr_; std::shared_ptr slow_down_start_pose_ptr_; diff --git a/system/autoware_default_adapi/src/planning.cpp b/system/autoware_default_adapi/src/planning.cpp index e11b01115caad..98f1c846d202e 100644 --- a/system/autoware_default_adapi/src/planning.cpp +++ b/system/autoware_default_adapi/src/planning.cpp @@ -44,6 +44,7 @@ const std::map conversion_map = { {"no_stopping_area", PlanningBehavior::NO_STOPPING_AREA}, {"blind_spot", PlanningBehavior::REAR_CHECK}, {"obstacle_cruise_planner", PlanningBehavior::ROUTE_OBSTACLE}, + {"obstacle_stop_planner", PlanningBehavior::ROUTE_OBSTACLE}, {"motion_velocity_planner", PlanningBehavior::ROUTE_OBSTACLE}, {"walkway", PlanningBehavior::SIDEWALK}, {"start_planner", PlanningBehavior::START_PLANNER}, @@ -215,6 +216,7 @@ PlanningNode::PlanningNode(const rclcpp::NodeOptions & options) : Node("planning "/planning/planning_factors/merge_from_private", "/planning/planning_factors/no_stopping_area", "/planning/planning_factors/obstacle_cruise_planner", + "/planning/planning_factors/obstacle_stop_planner", "/planning/planning_factors/occlusion_spot", "/planning/planning_factors/run_out", "/planning/planning_factors/stop_line", From 7bc6a4e109cfaafc44ec3cae2cf5ab44ed7190a4 Mon Sep 17 00:00:00 2001 From: Masaki Baba Date: Fri, 17 Jan 2025 13:53:12 +0900 Subject: [PATCH 52/61] fix(map_based_prediction): fix unintentional accumulation of lanelets (#9950) add clear before insert Signed-off-by: a-maumau --- perception/autoware_map_based_prediction/src/predictor_vru.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/perception/autoware_map_based_prediction/src/predictor_vru.cpp b/perception/autoware_map_based_prediction/src/predictor_vru.cpp index 0eea665cbd8a2..ffbdbd97b50a2 100644 --- a/perception/autoware_map_based_prediction/src/predictor_vru.cpp +++ b/perception/autoware_map_based_prediction/src/predictor_vru.cpp @@ -269,6 +269,7 @@ void PredictorVru::setLaneletMap(std::shared_ptr lanelet_ma const auto all_lanelets = lanelet::utils::query::laneletLayer(lanelet_map_ptr_); const auto crosswalks = lanelet::utils::query::crosswalkLanelets(all_lanelets); const auto walkways = lanelet::utils::query::walkwayLanelets(all_lanelets); + crosswalks_.clear(); crosswalks_.insert(crosswalks_.end(), crosswalks.begin(), crosswalks.end()); crosswalks_.insert(crosswalks_.end(), walkways.begin(), walkways.end()); From 74f677936177bc49c6af13032e00ee8e1b49eef5 Mon Sep 17 00:00:00 2001 From: Masato Saeki <78376491+MasatoSaeki@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:55:15 +0900 Subject: [PATCH 53/61] chore(autoware_traffic_light_map_based_detector): modify docs (#9817) * modify docs Signed-off-by: MasatoSaeki * fix title Signed-off-by: MasatoSaeki * fix docs Signed-off-by: MasatoSaeki * fix word Signed-off-by: MasatoSaeki * add comment about debug markers Signed-off-by: MasatoSaeki * fix docs Signed-off-by: MasatoSaeki --------- Signed-off-by: MasatoSaeki --- .../README.md | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/perception/autoware_traffic_light_map_based_detector/README.md b/perception/autoware_traffic_light_map_based_detector/README.md index 8a59db19ae64d..6ef54d448b415 100644 --- a/perception/autoware_traffic_light_map_based_detector/README.md +++ b/perception/autoware_traffic_light_map_based_detector/README.md @@ -1,4 +1,4 @@ -# The `autoware_traffic_light_map_based_detector` Package +# autoware_traffic_light_map_based_detector ## Overview @@ -9,34 +9,36 @@ Calibration and vibration errors can be entered as parameters, and the size of t ![traffic_light_map_based_detector_result](./docs/traffic_light_map_based_detector_result.svg) If the node receives route information, it only looks at traffic lights on that route. -If the node receives no route information, it looks at a radius of 200 meters and the angle between the traffic light and the camera is less than 40 degrees. +If the node receives no route information, it looks at them within a radius of `max_detection_range` and the angle between the traffic light and the camera is less than `car_traffic_light_max_angle_range` or `pedestrian_traffic_light_max_angle_range`. ## Input topics -| Name | Type | Description | -| -------------------- | ------------------------------------- | ----------------------- | -| `~input/vector_map` | autoware_map_msgs::msg::LaneletMapBin | vector map | -| `~input/camera_info` | sensor_msgs::CameraInfo | target camera parameter | -| `~input/route` | autoware_planning_msgs::LaneletRoute | optional: route | +| Name | Type | Description | +| --------------------- | ----------------------------------------- | ----------------------- | +| `~/input/vector_map` | autoware_map_msgs::msg::LaneletMapBin | vector map | +| `~/input/camera_info` | sensor_msgs::msg::CameraInfo | target camera parameter | +| `~/input/route` | autoware_planning_msgs::msg::LaneletRoute | optional: route | ## Output topics -| Name | Type | Description | -| ---------------- | ------------------------------------------- | -------------------------------------------------------------------- | -| `~output/rois` | tier4_perception_msgs::TrafficLightRoiArray | location of traffic lights in image corresponding to the camera info | -| `~expect/rois` | tier4_perception_msgs::TrafficLightRoiArray | location of traffic lights in image without any offset | -| `~debug/markers` | visualization_msgs::MarkerArray | visualization to debug | +| Name | Type | Description | +| ----------------- | ------------------------------------------------ | ------------------------------------------------------------------------- | +| `~/output/rois` | tier4_perception_msgs::msg::TrafficLightRoiArray | location of traffic lights in image corresponding to the camera info | +| `~/expect/rois` | tier4_perception_msgs::msg::TrafficLightRoiArray | location of traffic lights in image without any offset | +| `~/debug/markers` | visualization_msgs::msg::MarkerArray | markers which show a line that combines from camera to each traffic light | ## Node parameters -| Parameter | Type | Description | -| ---------------------- | ------ | --------------------------------------------------------------------- | -| `max_vibration_pitch` | double | Maximum error in pitch direction. If -5~+5, it will be 10. | -| `max_vibration_yaw` | double | Maximum error in yaw direction. If -5~+5, it will be 10. | -| `max_vibration_height` | double | Maximum error in height direction. If -5~+5, it will be 10. | -| `max_vibration_width` | double | Maximum error in width direction. If -5~+5, it will be 10. | -| `max_vibration_depth` | double | Maximum error in depth direction. If -5~+5, it will be 10. | -| `max_detection_range` | double | Maximum detection range in meters. Must be positive | -| `min_timestamp_offset` | double | Minimum timestamp offset when searching for corresponding tf | -| `max_timestamp_offset` | double | Maximum timestamp offset when searching for corresponding tf | -| `timestamp_sample_len` | double | sampling length between min_timestamp_offset and max_timestamp_offset | +| Parameter | Type | Description | +| ------------------------------------------ | ------ | ----------------------------------------------------------------------------------------------- | +| `max_vibration_pitch` | double | Maximum error in pitch direction. If -5~+5, it will be 10. | +| `max_vibration_yaw` | double | Maximum error in yaw direction. If -5~+5, it will be 10. | +| `max_vibration_height` | double | Maximum error in height direction. If -5~+5, it will be 10. | +| `max_vibration_width` | double | Maximum error in width direction. If -5~+5, it will be 10. | +| `max_vibration_depth` | double | Maximum error in depth direction. If -5~+5, it will be 10. | +| `max_detection_range` | double | Maximum detection range in meters. Must be positive. | +| `min_timestamp_offset` | double | Minimum timestamp offset when searching for corresponding tf. | +| `max_timestamp_offset` | double | Maximum timestamp offset when searching for corresponding tf. | +| `timestamp_sample_len` | double | Sampling length between min_timestamp_offset and max_timestamp_offset. | +| `car_traffic_light_max_angle_range` | double | Maximum angle between the vehicular traffic light and the camera in degrees. Must be positive. | +| `pedestrian_traffic_light_max_angle_range` | double | Maximum angle between the pedestrian traffic light and the camera in degrees. Must be positive. | From 849892ec367b052b07550413269c38667204510b Mon Sep 17 00:00:00 2001 From: Masato Saeki <78376491+MasatoSaeki@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:55:32 +0900 Subject: [PATCH 54/61] chore(autoware_traffic_light_fine_detector): modify docs and related params (#9818) * modify readme and related params Signed-off-by: MasatoSaeki * fix typo Signed-off-by: MasatoSaeki * fix Signed-off-by: MasatoSaeki --------- Signed-off-by: MasatoSaeki --- .../README.md | 19 ++++++++++--------- .../traffic_light_fine_detector.param.yaml | 1 + .../src/traffic_light_fine_detector_node.cpp | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/perception/autoware_traffic_light_fine_detector/README.md b/perception/autoware_traffic_light_fine_detector/README.md index 35b55c84aa087..df9f297422fce 100644 --- a/perception/autoware_traffic_light_fine_detector/README.md +++ b/perception/autoware_traffic_light_fine_detector/README.md @@ -1,8 +1,8 @@ -# traffic_light_fine_detector +# autoware_traffic_light_fine_detector ## Purpose -It is a package for traffic light detection using YoloX-s. +It is a package for traffic light detection using YOLOX-s. ## Training Information @@ -21,17 +21,18 @@ Please visit [autoware-documentation](https://github.com/autowarefoundation/auto ## Inner-workings / Algorithms -Based on the camera image and the global ROI array detected by `map_based_detection` node, a CNN-based detection method enables highly accurate traffic light detection. +Based on the camera image and the global ROI array detected by `map_based_detector` node, a CNN-based detection method enables highly accurate traffic light detection. If can not detect traffic light, x_offset, y_offset, height and width of output ROI become `0`. +ROIs detected from YOLOX will be selected by a combination of `expect/rois`. At this time, evaluate the whole as ROIs, not just the ROI alone. ## Inputs / Outputs ### Input -| Name | Type | Description | -| --------------- | -------------------------------------------------- | ------------------------------------------------------------------- | -| `~/input/image` | `sensor_msgs/Image` | The full size camera image | -| `~/input/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | The array of ROIs detected by map_based_detector | -| `~/expect/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | The array of ROIs detected by map_based_detector without any offset | +| Name | Type | Description | +| --------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| `~/input/image` | `sensor_msgs::msg::Image` | The full size camera image | +| `~/input/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | The array of ROIs detected by map_based_detector | +| `~/expect/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | The array of ROIs detected by map_based_detector without any offset, used to select the best detection results | ### Output @@ -56,7 +57,7 @@ Based on the camera image and the global ROI array detected by `map_based_detect | `data_path` | string | "$(env HOME)/autoware_data" | packages data and artifacts directory path | | `fine_detector_model_path` | string | "" | The onnx file name for yolo model | | `fine_detector_label_path` | string | "" | The label file with label names for detected objects written on it | -| `fine_detector_precision` | string | "fp32" | The inference mode: "fp32", "fp16" | +| `fine_detector_precision` | string | "fp16" | The inference mode: "fp32", "fp16" | | `approximate_sync` | bool | false | Flag for whether to ues approximate sync policy | | `gpu_id` | integer | 0 | ID for the selecting CUDA GPU device | diff --git a/perception/autoware_traffic_light_fine_detector/config/traffic_light_fine_detector.param.yaml b/perception/autoware_traffic_light_fine_detector/config/traffic_light_fine_detector.param.yaml index 36d4413472a0b..b647729a27de5 100644 --- a/perception/autoware_traffic_light_fine_detector/config/traffic_light_fine_detector.param.yaml +++ b/perception/autoware_traffic_light_fine_detector/config/traffic_light_fine_detector.param.yaml @@ -5,4 +5,5 @@ fine_detector_precision: fp16 fine_detector_score_thresh: 0.3 fine_detector_nms_thresh: 0.65 + approximate_sync: false gpu_id: 0 diff --git a/perception/autoware_traffic_light_fine_detector/src/traffic_light_fine_detector_node.cpp b/perception/autoware_traffic_light_fine_detector/src/traffic_light_fine_detector_node.cpp index d9e0471a43d62..bc3d29ce456a8 100644 --- a/perception/autoware_traffic_light_fine_detector/src/traffic_light_fine_detector_node.cpp +++ b/perception/autoware_traffic_light_fine_detector/src/traffic_light_fine_detector_node.cpp @@ -61,7 +61,7 @@ TrafficLightFineDetectorNode::TrafficLightFineDetectorNode(const rclcpp::NodeOpt std::string model_path = declare_parameter("fine_detector_model_path", ""); std::string label_path = declare_parameter("fine_detector_label_path", ""); - std::string precision = declare_parameter("fine_detector_precision", "fp32"); + std::string precision = declare_parameter("fine_detector_precision", "fp16"); const uint8_t gpu_id = declare_parameter("gpu_id", 0); // Objects with a score lower than this value will be ignored. // This threshold will be ignored if specified model contains EfficientNMS_TRT module in it From bce4c44a7416f076071fa62bde37b1d21cc8e42d Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:33:32 +0900 Subject: [PATCH 55/61] =?UTF-8?q?feat:=20tier4=5Fdebug=5Fmsgs=20changed=20?= =?UTF-8?q?to=20autoware=5Finternal=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(?= =?UTF-8?q?#9853)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files control/autoware_trajectory_follower_node Signed-off-by: vish0012 --- control/autoware_trajectory_follower_node/README.md | 2 +- .../autoware/trajectory_follower_node/controller_node.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/control/autoware_trajectory_follower_node/README.md b/control/autoware_trajectory_follower_node/README.md index ac05dd67f18e6..c56154f909d1a 100644 --- a/control/autoware_trajectory_follower_node/README.md +++ b/control/autoware_trajectory_follower_node/README.md @@ -151,7 +151,7 @@ Giving the longitudinal controller information about steer convergence allows it ## Debugging -Debug information are published by the lateral and longitudinal controller using `tier4_debug_msgs/Float32MultiArrayStamped` messages. +Debug information are published by the lateral and longitudinal controller using `autoware_internal_debug_msgs/Float32MultiArrayStamped` messages. A configuration file for [PlotJuggler](https://github.com/facontidavide/PlotJuggler) is provided in the `config` folder which, when loaded, allow to automatically subscribe and visualize information useful for debugging. diff --git a/control/autoware_trajectory_follower_node/include/autoware/trajectory_follower_node/controller_node.hpp b/control/autoware_trajectory_follower_node/include/autoware/trajectory_follower_node/controller_node.hpp index 1733b4bcbbb7d..c84355cc202fa 100644 --- a/control/autoware_trajectory_follower_node/include/autoware/trajectory_follower_node/controller_node.hpp +++ b/control/autoware_trajectory_follower_node/include/autoware/trajectory_follower_node/controller_node.hpp @@ -44,7 +44,7 @@ #include "tf2_msgs/msg/tf_message.hpp" #include "visualization_msgs/msg/marker_array.hpp" #include -#include +#include #include #include @@ -63,7 +63,7 @@ namespace trajectory_follower_node using autoware::universe_utils::StopWatch; using autoware_adapi_v1_msgs::msg::OperationModeState; using autoware_control_msgs::msg::ControlHorizon; -using tier4_debug_msgs::msg::Float64Stamped; +using autoware_internal_debug_msgs::msg::Float64Stamped; namespace trajectory_follower = ::autoware::motion::control::trajectory_follower; From dc75c7ff53ce2e5e1aaafd289a19e8d1e11c559b Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:36:27 +0900 Subject: [PATCH 56/61] =?UTF-8?q?feat:=20tier4=5Fdebug=5Fmsgs=20changed=20?= =?UTF-8?q?to=20autoware=5Finternal=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(?= =?UTF-8?q?#9851)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../training_and_data_check/rosbag2.bash | 32 +++++++++---------- .../scripts/pympc_trajectory_follower.py | 6 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/control/autoware_smart_mpc_trajectory_follower/autoware_smart_mpc_trajectory_follower/training_and_data_check/rosbag2.bash b/control/autoware_smart_mpc_trajectory_follower/autoware_smart_mpc_trajectory_follower/training_and_data_check/rosbag2.bash index d2687b352a17d..7a50a7e118298 100644 --- a/control/autoware_smart_mpc_trajectory_follower/autoware_smart_mpc_trajectory_follower/training_and_data_check/rosbag2.bash +++ b/control/autoware_smart_mpc_trajectory_follower/autoware_smart_mpc_trajectory_follower/training_and_data_check/rosbag2.bash @@ -7,27 +7,27 @@ gnome-terminal -- bash -c 'ros2 topic echo /vehicle/status/steering_status autow gnome-terminal -- bash -c 'ros2 topic echo /control/command/control_cmd autoware_control_msgs/msg/Control --csv --qos-history keep_all --qos-reliability reliable > control_cmd.csv' gnome-terminal -- bash -c 'ros2 topic echo /control/trajectory_follower/control_cmd autoware_control_msgs/msg/Control --csv --qos-history keep_all --qos-reliability reliable > control_cmd_orig.csv' -gnome-terminal -- bash -c 'ros2 topic echo /control/trajectory_follower/lane_departure_checker_node/debug/deviation/lateral tier4_debug_msgs/msg/Float64Stamped --csv --qos-history keep_all --qos-reliability reliable > lateral_error.csv' -gnome-terminal -- bash -c 'ros2 topic echo /control/trajectory_follower/lane_departure_checker_node/debug/deviation/yaw tier4_debug_msgs/msg/Float64Stamped --csv --qos-history keep_all --qos-reliability reliable > yaw_error.csv' +gnome-terminal -- bash -c 'ros2 topic echo /control/trajectory_follower/lane_departure_checker_node/debug/deviation/lateral autoware_internal_debug_msgs/msg/Float64Stamped --csv --qos-history keep_all --qos-reliability reliable > lateral_error.csv' +gnome-terminal -- bash -c 'ros2 topic echo /control/trajectory_follower/lane_departure_checker_node/debug/deviation/yaw autoware_internal_debug_msgs/msg/Float64Stamped --csv --qos-history keep_all --qos-reliability reliable > yaw_error.csv' gnome-terminal -- bash -c 'ros2 topic echo /system/operation_mode/state autoware_adapi_v1_msgs/msg/OperationModeState --csv --qos-history keep_all --qos-reliability reliable > system_operation_mode_state.csv' gnome-terminal -- bash -c 'ros2 topic echo /vehicle/status/control_mode autoware_vehicle_msgs/msg/ControlModeReport --csv --qos-history keep_all --qos-reliability reliable > vehicle_status_control_mode.csv' gnome-terminal -- bash -c 'ros2 topic echo /sensing/imu/imu_data sensor_msgs/msg/Imu --csv --qos-history keep_all --qos-reliability reliable > imu.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_x_des tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_x_des.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_y_des tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_y_des.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_v_des tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_v_des.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_yaw_des tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_yaw_des.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_acc_des tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_acc_des.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_steer_des tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_steer_des.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_X_des_converted tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_X_des_converted.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_x_current tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_x_current.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_error_prediction tier4_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_error_prediction.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_max_trajectory_err tier4_debug_msgs/msg/Float32Stamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_max_trajectory_err.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_emergency_stop_mode tier4_debug_msgs/msg/BoolStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_emergency_stop_mode.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_goal_stop_mode tier4_debug_msgs/msg/BoolStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_goal_stop_mode.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_total_ctrl_time tier4_debug_msgs/msg/Float32Stamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_total_ctrl_time.csv' -gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_calc_u_opt_time tier4_debug_msgs/msg/Float32Stamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_calc_u_opt_time.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_x_des autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_x_des.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_y_des autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_y_des.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_v_des autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_v_des.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_yaw_des autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_yaw_des.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_acc_des autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_acc_des.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_steer_des autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_steer_des.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_X_des_converted autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_X_des_converted.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_x_current autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_x_current.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_error_prediction autoware_internal_debug_msgs/msg/Float32MultiArrayStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_error_prediction.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_max_trajectory_err autoware_internal_debug_msgs/msg/Float32Stamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_max_trajectory_err.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_emergency_stop_mode autoware_internal_debug_msgs/msg/BoolStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_emergency_stop_mode.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_goal_stop_mode autoware_internal_debug_msgs/msg/BoolStamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_goal_stop_mode.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_total_ctrl_time autoware_internal_debug_msgs/msg/Float32Stamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_total_ctrl_time.csv' +gnome-terminal -- bash -c 'ros2 topic echo /debug_mpc_calc_u_opt_time autoware_internal_debug_msgs/msg/Float32Stamped --csv --qos-history keep_all --qos-reliability reliable > debug_mpc_calc_u_opt_time.csv' # wait a moment to open new terminals converting rosbag2 to csv sleep 8 diff --git a/control/autoware_smart_mpc_trajectory_follower/scripts/pympc_trajectory_follower.py b/control/autoware_smart_mpc_trajectory_follower/scripts/pympc_trajectory_follower.py index f767dad223f0d..104261866cf98 100755 --- a/control/autoware_smart_mpc_trajectory_follower/scripts/pympc_trajectory_follower.py +++ b/control/autoware_smart_mpc_trajectory_follower/scripts/pympc_trajectory_follower.py @@ -21,6 +21,9 @@ from autoware_adapi_v1_msgs.msg import OperationModeState from autoware_control_msgs.msg import Control +from autoware_internal_debug_msgs.msg import BoolStamped +from autoware_internal_debug_msgs.msg import Float32MultiArrayStamped +from autoware_internal_debug_msgs.msg import Float32Stamped from autoware_planning_msgs.msg import Trajectory from autoware_planning_msgs.msg import TrajectoryPoint from autoware_smart_mpc_trajectory_follower.scripts import drive_controller @@ -43,9 +46,6 @@ from scipy.spatial.transform import Rotation as R from scipy.spatial.transform import Slerp from std_msgs.msg import String -from tier4_debug_msgs.msg import BoolStamped -from tier4_debug_msgs.msg import Float32MultiArrayStamped -from tier4_debug_msgs.msg import Float32Stamped from visualization_msgs.msg import Marker from visualization_msgs.msg import MarkerArray From 2a6663b27472695357628bdc106494ae3ad85a4f Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:36:46 +0900 Subject: [PATCH 57/61] =?UTF-8?q?feat(autoware=5Fdetected=5Fobject=5Fvalid?= =?UTF-8?q?ation):=20tier4=5Fdebug=5Fmsgs=20changed=20to=20autoware=5Finte?= =?UTF-8?q?rnal=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(#9871)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files perception/autoware_detected_object_validation Signed-off-by: vish0012 Co-authored-by: Ryohsuke Mitsudome <43976834+mitsudome-r@users.noreply.github.com> --- .../src/lanelet_filter/lanelet_filter.cpp | 4 ++-- .../src/obstacle_pointcloud/obstacle_pointcloud_validator.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/perception/autoware_detected_object_validation/src/lanelet_filter/lanelet_filter.cpp b/perception/autoware_detected_object_validation/src/lanelet_filter/lanelet_filter.cpp index f91c4e2036227..f1c25e8573e85 100644 --- a/perception/autoware_detected_object_validation/src/lanelet_filter/lanelet_filter.cpp +++ b/perception/autoware_detected_object_validation/src/lanelet_filter/lanelet_filter.cpp @@ -180,9 +180,9 @@ void ObjectLaneletFilterNode::objectCallback( std::chrono::nanoseconds( (this->get_clock()->now() - output_object_msg.header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug/pipeline_latency_ms", pipeline_latency); - debug_publisher_->publish( + debug_publisher_->publish( "debug/processing_time_ms", stop_watch_ptr_->toc("processing_time", true)); } diff --git a/perception/autoware_detected_object_validation/src/obstacle_pointcloud/obstacle_pointcloud_validator.cpp b/perception/autoware_detected_object_validation/src/obstacle_pointcloud/obstacle_pointcloud_validator.cpp index 979cdd3909f14..0c69b45291281 100644 --- a/perception/autoware_detected_object_validation/src/obstacle_pointcloud/obstacle_pointcloud_validator.cpp +++ b/perception/autoware_detected_object_validation/src/obstacle_pointcloud/obstacle_pointcloud_validator.cpp @@ -386,7 +386,7 @@ void ObstaclePointCloudBasedValidator::onObjectsAndObstaclePointCloud( std::chrono::duration( std::chrono::nanoseconds((this->get_clock()->now() - output.header.stamp).nanoseconds())) .count(); - debug_publisher_->publish( + debug_publisher_->publish( "debug/pipeline_latency_ms", pipeline_latency); } From aa95f2a4f27f847532006e16ceee4d458a32d515 Mon Sep 17 00:00:00 2001 From: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:07:04 +0900 Subject: [PATCH 58/61] chore(planning): move package directory for planning factor interface (#9948) * chore: add new package for planning factor interface Signed-off-by: satoshi-ota * chore(surround_obstacle_checker): update include file Signed-off-by: satoshi-ota * chore(obstacle_stop_planner): update include file Signed-off-by: satoshi-ota * chore(obstacle_cruise_planner): update include file Signed-off-by: satoshi-ota * chore(motion_velocity_planner): update include file Signed-off-by: satoshi-ota * chore(bpp): update include file Signed-off-by: satoshi-ota * chore(bvp-common): update include file Signed-off-by: satoshi-ota * chore(blind_spot): update include file Signed-off-by: satoshi-ota * chore(crosswalk): update include file Signed-off-by: satoshi-ota * chore(detection_area): update include file Signed-off-by: satoshi-ota * chore(intersection): update include file Signed-off-by: satoshi-ota * chore(no_drivable_area): update include file Signed-off-by: satoshi-ota * chore(no_stopping_area): update include file Signed-off-by: satoshi-ota * chore(occlusion_spot): update include file Signed-off-by: satoshi-ota * chore(run_out): update include file Signed-off-by: satoshi-ota * chore(speed_bump): update include file Signed-off-by: satoshi-ota * chore(stop_line): update include file Signed-off-by: satoshi-ota * chore(template_module): update include file Signed-off-by: satoshi-ota * chore(traffic_light): update include file Signed-off-by: satoshi-ota * chore(vtl): update include file Signed-off-by: satoshi-ota * chore(walkway): update include file Signed-off-by: satoshi-ota * chore(motion_utils): remove factor interface Signed-off-by: satoshi-ota --------- Signed-off-by: satoshi-ota --- .../factor/steering_factor_interface.hpp | 51 ---------------- .../factor/velocity_factor_interface.hpp | 57 ----------------- .../src/factor/steering_factor_interface.cpp | 34 ----------- .../src/factor/velocity_factor_interface.cpp | 61 ------------------- .../planner_interface.hpp | 8 ++- .../package.xml | 1 + .../package.xml | 1 + .../src/debug_marker.cpp | 5 +- .../src/debug_marker.hpp | 5 +- .../CMakeLists.txt | 11 ++++ .../README.md | 1 + .../planning_factor_interface.hpp | 10 +-- .../package.xml | 29 +++++++++ .../src}/planing_factor_interface.cpp | 6 +- .../package.xml | 1 + .../src/debug_marker.cpp | 3 +- .../src/debug_marker.hpp | 5 +- .../behavior_path_planner_node.hpp | 4 +- .../package.xml | 1 + .../interface/scene_module_interface.hpp | 4 +- .../package.xml | 1 + .../scene.hpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene_crosswalk.cpp | 3 +- .../src/scene_crosswalk.hpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../src/scene_intersection.cpp | 27 ++++---- .../src/scene_intersection.hpp | 3 +- .../src/scene_merge_from_private_road.cpp | 3 +- .../src/scene_merge_from_private_road.hpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../src/scene_no_stopping_area.cpp | 3 +- .../src/scene_no_stopping_area.hpp | 3 +- .../src/scene_occlusion_spot.cpp | 3 +- .../src/scene_occlusion_spot.hpp | 3 +- .../scene_module_interface.hpp | 11 ++-- .../package.xml | 1 + .../src/scene_module_interface.cpp | 3 +- .../scene_module_interface_with_rtc.hpp | 3 +- .../package.xml | 1 + .../src/scene_module_interface_with_rtc.cpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../test/test_scene.cpp | 2 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../src/scene.cpp | 3 +- .../src/scene.hpp | 3 +- .../src/scene_walkway.cpp | 3 +- .../src/scene_walkway.hpp | 3 +- .../src/dynamic_obstacle_stop_module.cpp | 5 +- .../src/out_of_lane_module.cpp | 3 +- .../plugin_module_interface.hpp | 5 +- .../package.xml | 1 + 62 files changed, 170 insertions(+), 281 deletions(-) delete mode 100644 common/autoware_motion_utils/include/autoware/motion_utils/factor/steering_factor_interface.hpp delete mode 100644 common/autoware_motion_utils/include/autoware/motion_utils/factor/velocity_factor_interface.hpp delete mode 100644 common/autoware_motion_utils/src/factor/steering_factor_interface.cpp delete mode 100644 common/autoware_motion_utils/src/factor/velocity_factor_interface.cpp create mode 100644 planning/autoware_planning_factor_interface/CMakeLists.txt create mode 100644 planning/autoware_planning_factor_interface/README.md rename {common/autoware_motion_utils/include/autoware/motion_utils/factor => planning/autoware_planning_factor_interface/include/autoware/planning_factor_interface}/planning_factor_interface.hpp (96%) create mode 100644 planning/autoware_planning_factor_interface/package.xml rename {common/autoware_motion_utils/src/factor => planning/autoware_planning_factor_interface/src}/planing_factor_interface.cpp (93%) diff --git a/common/autoware_motion_utils/include/autoware/motion_utils/factor/steering_factor_interface.hpp b/common/autoware_motion_utils/include/autoware/motion_utils/factor/steering_factor_interface.hpp deleted file mode 100644 index 5b701a73ac543..0000000000000 --- a/common/autoware_motion_utils/include/autoware/motion_utils/factor/steering_factor_interface.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2022 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__MOTION_UTILS__FACTOR__STEERING_FACTOR_INTERFACE_HPP_ -#define AUTOWARE__MOTION_UTILS__FACTOR__STEERING_FACTOR_INTERFACE_HPP_ - -#include -#include -#include - -#include - -namespace autoware::motion_utils -{ - -using autoware_adapi_v1_msgs::msg::PlanningBehavior; -using autoware_adapi_v1_msgs::msg::SteeringFactor; -using SteeringFactorBehavior = SteeringFactor::_behavior_type; -using SteeringFactorStatus = SteeringFactor::_status_type; -using geometry_msgs::msg::Pose; - -class SteeringFactorInterface -{ -public: - [[nodiscard]] SteeringFactor get() const { return steering_factor_; } - void init(const SteeringFactorBehavior & behavior) { behavior_ = behavior; } - void reset() { steering_factor_.behavior = PlanningBehavior::UNKNOWN; } - - void set( - const std::array & pose, const std::array distance, - const uint16_t direction, const uint16_t status, const std::string & detail = ""); - -private: - SteeringFactorBehavior behavior_{SteeringFactor::UNKNOWN}; - SteeringFactor steering_factor_{}; -}; - -} // namespace autoware::motion_utils - -#endif // AUTOWARE__MOTION_UTILS__FACTOR__STEERING_FACTOR_INTERFACE_HPP_ diff --git a/common/autoware_motion_utils/include/autoware/motion_utils/factor/velocity_factor_interface.hpp b/common/autoware_motion_utils/include/autoware/motion_utils/factor/velocity_factor_interface.hpp deleted file mode 100644 index 2fcde52ec7c81..0000000000000 --- a/common/autoware_motion_utils/include/autoware/motion_utils/factor/velocity_factor_interface.hpp +++ /dev/null @@ -1,57 +0,0 @@ - -// Copyright 2022-2024 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef AUTOWARE__MOTION_UTILS__FACTOR__VELOCITY_FACTOR_INTERFACE_HPP_ -#define AUTOWARE__MOTION_UTILS__FACTOR__VELOCITY_FACTOR_INTERFACE_HPP_ - -#include -#include -#include -#include - -#include -#include - -namespace autoware::motion_utils -{ -using autoware_adapi_v1_msgs::msg::PlanningBehavior; -using autoware_adapi_v1_msgs::msg::VelocityFactor; -using VelocityFactorBehavior = VelocityFactor::_behavior_type; -using VelocityFactorStatus = VelocityFactor::_status_type; -using geometry_msgs::msg::Pose; - -class VelocityFactorInterface -{ -public: - [[nodiscard]] VelocityFactor get() const { return velocity_factor_; } - void init(const VelocityFactorBehavior & behavior) { behavior_ = behavior; } - void reset() { velocity_factor_.behavior = PlanningBehavior::UNKNOWN; } - - template - void set( - const std::vector & points, const Pose & curr_pose, const Pose & stop_pose, - const VelocityFactorStatus status, const std::string & detail = ""); - - void set( - const double & distance, const VelocityFactorStatus & status, const std::string & detail = ""); - -private: - VelocityFactorBehavior behavior_{VelocityFactor::UNKNOWN}; - VelocityFactor velocity_factor_{}; -}; - -} // namespace autoware::motion_utils - -#endif // AUTOWARE__MOTION_UTILS__FACTOR__VELOCITY_FACTOR_INTERFACE_HPP_ diff --git a/common/autoware_motion_utils/src/factor/steering_factor_interface.cpp b/common/autoware_motion_utils/src/factor/steering_factor_interface.cpp deleted file mode 100644 index 7f12e2972ec86..0000000000000 --- a/common/autoware_motion_utils/src/factor/steering_factor_interface.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2022 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include - -namespace autoware::motion_utils -{ -void SteeringFactorInterface::set( - const std::array & pose, const std::array distance, const uint16_t direction, - const uint16_t status, const std::string & detail) -{ - steering_factor_.pose = pose; - std::array converted_distance{0.0, 0.0}; - for (int i = 0; i < 2; ++i) converted_distance[i] = static_cast(distance[i]); - steering_factor_.distance = converted_distance; - steering_factor_.behavior = behavior_; - steering_factor_.direction = direction; - steering_factor_.status = status; - steering_factor_.detail = detail; -} -} // namespace autoware::motion_utils diff --git a/common/autoware_motion_utils/src/factor/velocity_factor_interface.cpp b/common/autoware_motion_utils/src/factor/velocity_factor_interface.cpp deleted file mode 100644 index cfa3c91eac43e..0000000000000 --- a/common/autoware_motion_utils/src/factor/velocity_factor_interface.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2023-2024 TIER IV, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include -#include -#include - -#include -#include - -namespace autoware::motion_utils -{ -template -void VelocityFactorInterface::set( - const std::vector & points, const Pose & curr_pose, const Pose & stop_pose, - const VelocityFactorStatus status, const std::string & detail) -{ - const auto & curr_point = curr_pose.position; - const auto & stop_point = stop_pose.position; - velocity_factor_.behavior = behavior_; - velocity_factor_.pose = stop_pose; - velocity_factor_.distance = - static_cast(autoware::motion_utils::calcSignedArcLength(points, curr_point, stop_point)); - velocity_factor_.status = status; - velocity_factor_.detail = detail; -} - -void VelocityFactorInterface::set( - const double & distance, const VelocityFactorStatus & status, const std::string & detail) -{ - velocity_factor_.behavior = behavior_; - velocity_factor_.distance = static_cast(distance); - velocity_factor_.status = status; - velocity_factor_.detail = detail; -} - -template void VelocityFactorInterface::set( - const std::vector &, const Pose &, const Pose &, - const VelocityFactorStatus, const std::string &); -template void VelocityFactorInterface::set( - const std::vector &, const Pose &, const Pose &, - const VelocityFactorStatus, const std::string &); -template void VelocityFactorInterface::set( - const std::vector &, const Pose &, const Pose &, - const VelocityFactorStatus, const std::string &); - -} // namespace autoware::motion_utils diff --git a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp index 823771e173c48..f5e183afd12bd 100644 --- a/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp +++ b/planning/autoware_obstacle_cruise_planner/include/autoware/obstacle_cruise_planner/planner_interface.hpp @@ -15,12 +15,12 @@ #ifndef AUTOWARE__OBSTACLE_CRUISE_PLANNER__PLANNER_INTERFACE_HPP_ #define AUTOWARE__OBSTACLE_CRUISE_PLANNER__PLANNER_INTERFACE_HPP_ -#include "autoware/motion_utils/factor/planning_factor_interface.hpp" #include "autoware/motion_utils/trajectory/trajectory.hpp" #include "autoware/obstacle_cruise_planner/common_structs.hpp" #include "autoware/obstacle_cruise_planner/stop_planning_debug_info.hpp" #include "autoware/obstacle_cruise_planner/type_alias.hpp" #include "autoware/obstacle_cruise_planner/utils.hpp" +#include "autoware/planning_factor_interface/planning_factor_interface.hpp" #include "autoware/universe_utils/ros/update_param.hpp" #include "autoware/universe_utils/system/stop_watch.hpp" @@ -48,7 +48,8 @@ class PlannerInterface rclcpp::Node & node, const LongitudinalInfo & longitudinal_info, const autoware::vehicle_info_utils::VehicleInfo & vehicle_info, const EgoNearestParam & ego_nearest_param, const std::shared_ptr debug_data_ptr) - : planning_factor_interface_{std::make_unique( + : planning_factor_interface_{std::make_unique< + autoware::planning_factor_interface::PlanningFactorInterface>( &node, "obstacle_cruise_planner")}, longitudinal_info_(longitudinal_info), vehicle_info_(vehicle_info), @@ -130,7 +131,8 @@ class PlannerInterface double getSafeDistanceMargin() const { return longitudinal_info_.safe_distance_margin; } protected: - std::unique_ptr planning_factor_interface_; + std::unique_ptr + planning_factor_interface_; // Parameters bool enable_debug_info_{false}; diff --git a/planning/autoware_obstacle_cruise_planner/package.xml b/planning/autoware_obstacle_cruise_planner/package.xml index 7c6d0b286c9b0..71c3b1fb1e0d5 100644 --- a/planning/autoware_obstacle_cruise_planner/package.xml +++ b/planning/autoware_obstacle_cruise_planner/package.xml @@ -25,6 +25,7 @@ autoware_objects_of_interest_marker_interface autoware_osqp_interface autoware_perception_msgs + autoware_planning_factor_interface autoware_planning_msgs autoware_planning_test_manager autoware_signal_processing diff --git a/planning/autoware_obstacle_stop_planner/package.xml b/planning/autoware_obstacle_stop_planner/package.xml index c9c78b3e87c3b..ba6364a2b59ee 100644 --- a/planning/autoware_obstacle_stop_planner/package.xml +++ b/planning/autoware_obstacle_stop_planner/package.xml @@ -23,6 +23,7 @@ autoware_adapi_v1_msgs autoware_motion_utils autoware_perception_msgs + autoware_planning_factor_interface autoware_planning_msgs autoware_planning_test_manager autoware_signal_processing diff --git a/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp b/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp index 62b9ae124f555..a3337c5dd2524 100644 --- a/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp +++ b/planning/autoware_obstacle_stop_planner/src/debug_marker.cpp @@ -47,8 +47,9 @@ ObstacleStopPlannerDebugNode::ObstacleStopPlannerDebugNode( rclcpp::Node * node, const double base_link2front) : node_(node), base_link2front_(base_link2front), - planning_factor_interface_{std::make_unique( - node, "obstacle_stop_planner")} + planning_factor_interface_{ + std::make_unique( + node, "obstacle_stop_planner")} { virtual_wall_pub_ = node_->create_publisher("~/virtual_wall", 1); debug_viz_pub_ = node_->create_publisher("~/debug/marker", 1); diff --git a/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp b/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp index dd9e5e3af1b3d..72e2b52c287f1 100644 --- a/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp +++ b/planning/autoware_obstacle_stop_planner/src/debug_marker.hpp @@ -14,7 +14,7 @@ #ifndef DEBUG_MARKER_HPP_ #define DEBUG_MARKER_HPP_ -#include +#include #include #include @@ -119,7 +119,8 @@ class ObstacleStopPlannerDebugNode rclcpp::Node * node_; double base_link2front_; - std::unique_ptr planning_factor_interface_; + std::unique_ptr + planning_factor_interface_; std::shared_ptr stop_pose_ptr_; std::shared_ptr target_stop_pose_ptr_; diff --git a/planning/autoware_planning_factor_interface/CMakeLists.txt b/planning/autoware_planning_factor_interface/CMakeLists.txt new file mode 100644 index 0000000000000..0c25a2c21fa19 --- /dev/null +++ b/planning/autoware_planning_factor_interface/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.14) +project(autoware_planning_factor_interface) + +find_package(autoware_cmake REQUIRED) +autoware_package() + +ament_auto_add_library(autoware_planning_factor_interface SHARED + DIRECTORY src +) + +ament_auto_package() diff --git a/planning/autoware_planning_factor_interface/README.md b/planning/autoware_planning_factor_interface/README.md new file mode 100644 index 0000000000000..7f715790995ba --- /dev/null +++ b/planning/autoware_planning_factor_interface/README.md @@ -0,0 +1 @@ +# planning factor interface diff --git a/common/autoware_motion_utils/include/autoware/motion_utils/factor/planning_factor_interface.hpp b/planning/autoware_planning_factor_interface/include/autoware/planning_factor_interface/planning_factor_interface.hpp similarity index 96% rename from common/autoware_motion_utils/include/autoware/motion_utils/factor/planning_factor_interface.hpp rename to planning/autoware_planning_factor_interface/include/autoware/planning_factor_interface/planning_factor_interface.hpp index 7b720c69c6701..a2325b197853d 100644 --- a/common/autoware_motion_utils/include/autoware/motion_utils/factor/planning_factor_interface.hpp +++ b/planning/autoware_planning_factor_interface/include/autoware/planning_factor_interface/planning_factor_interface.hpp @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef AUTOWARE__MOTION_UTILS__FACTOR__PLANNING_FACTOR_INTERFACE_HPP_ -#define AUTOWARE__MOTION_UTILS__FACTOR__PLANNING_FACTOR_INTERFACE_HPP_ +#ifndef AUTOWARE__PLANNING_FACTOR_INTERFACE__PLANNING_FACTOR_INTERFACE_HPP_ +#define AUTOWARE__PLANNING_FACTOR_INTERFACE__PLANNING_FACTOR_INTERFACE_HPP_ #include #include @@ -30,7 +30,7 @@ #include #include -namespace autoware::motion_utils +namespace autoware::planning_factor_interface { using geometry_msgs::msg::Pose; @@ -235,6 +235,6 @@ extern template void PlanningFactorInterface::add + + + autoware_planning_factor_interface + 0.40.0 + The autoware_planning_factor_interface package + Satoshi Ota + Mamoru Sobue + Apache License 2.0 + + Satoshi Ota + + ament_cmake_auto + autoware_cmake + + autoware_motion_utils + autoware_planning_msgs + autoware_universe_utils + rclcpp + tier4_planning_msgs + + ament_cmake_ros + ament_lint_auto + autoware_lint_common + + + ament_cmake + + diff --git a/common/autoware_motion_utils/src/factor/planing_factor_interface.cpp b/planning/autoware_planning_factor_interface/src/planing_factor_interface.cpp similarity index 93% rename from common/autoware_motion_utils/src/factor/planing_factor_interface.cpp rename to planning/autoware_planning_factor_interface/src/planing_factor_interface.cpp index d09355b4003ae..6578776dddc4f 100644 --- a/common/autoware_motion_utils/src/factor/planing_factor_interface.cpp +++ b/planning/autoware_planning_factor_interface/src/planing_factor_interface.cpp @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include #include #include -namespace autoware::motion_utils +namespace autoware::planning_factor_interface { template void PlanningFactorInterface::add( const std::vector &, const Pose &, const Pose &, @@ -44,4 +44,4 @@ template void PlanningFactorInterface::add &, const Pose &, const Pose &, const Pose &, const uint16_t behavior, const SafetyFactorArray &, const bool, const double, const double, const std::string &); -} // namespace autoware::motion_utils +} // namespace autoware::planning_factor_interface diff --git a/planning/autoware_surround_obstacle_checker/package.xml b/planning/autoware_surround_obstacle_checker/package.xml index 8bbc0b6bf4e02..d92223fb2ea5d 100644 --- a/planning/autoware_surround_obstacle_checker/package.xml +++ b/planning/autoware_surround_obstacle_checker/package.xml @@ -16,6 +16,7 @@ autoware_motion_utils autoware_perception_msgs + autoware_planning_factor_interface autoware_planning_msgs autoware_planning_test_manager autoware_universe_utils diff --git a/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp b/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp index 2acf6ba1c92f5..e34315ad986a5 100644 --- a/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp +++ b/planning/autoware_surround_obstacle_checker/src/debug_marker.cpp @@ -67,7 +67,8 @@ SurroundObstacleCheckerDebugNode::SurroundObstacleCheckerDebugNode( const double & surround_check_back_distance, const double & surround_check_hysteresis_distance, const geometry_msgs::msg::Pose & self_pose, const rclcpp::Clock::SharedPtr clock, rclcpp::Node & node) -: planning_factor_interface_{std::make_unique( +: planning_factor_interface_{std::make_unique< + autoware::planning_factor_interface::PlanningFactorInterface>( &node, "surround_obstacle_checker")}, vehicle_info_(vehicle_info), object_label_(object_label), diff --git a/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp b/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp index c49e277f2dc6c..0569c6815a252 100644 --- a/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp +++ b/planning/autoware_surround_obstacle_checker/src/debug_marker.hpp @@ -15,7 +15,7 @@ #ifndef DEBUG_MARKER_HPP_ #define DEBUG_MARKER_HPP_ -#include +#include #include #include @@ -70,7 +70,8 @@ class SurroundObstacleCheckerDebugNode rclcpp::Publisher::SharedPtr vehicle_footprint_offset_pub_; rclcpp::Publisher::SharedPtr vehicle_footprint_recover_offset_pub_; - std::unique_ptr planning_factor_interface_; + std::unique_ptr + planning_factor_interface_; autoware::vehicle_info_utils::VehicleInfo vehicle_info_; std::string object_label_; diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp b/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp index 7f7ecd7326b08..ba3d3d5d7a4d4 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner/include/autoware/behavior_path_planner/behavior_path_planner_node.hpp @@ -20,7 +20,7 @@ #include "autoware/universe_utils/ros/logger_level_configure.hpp" #include "planner_manager.hpp" -#include +#include #include #include @@ -51,7 +51,7 @@ namespace autoware::behavior_path_planner { -using autoware::motion_utils::PlanningFactorInterface; +using autoware::planning_factor_interface::PlanningFactorInterface; using autoware_adapi_v1_msgs::msg::OperationModeState; using autoware_map_msgs::msg::LaneletMapBin; using autoware_perception_msgs::msg::PredictedObject; diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner/package.xml b/planning/behavior_path_planner/autoware_behavior_path_planner/package.xml index f9c736b9d5dde..3f41ebe74c86d 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner/package.xml +++ b/planning/behavior_path_planner/autoware_behavior_path_planner/package.xml @@ -48,6 +48,7 @@ autoware_object_recognition_utils autoware_path_sampler autoware_perception_msgs + autoware_planning_factor_interface autoware_planning_msgs autoware_planning_test_manager autoware_signal_processing diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp b/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp index c96bc601b6403..741d4552d8558 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp +++ b/planning/behavior_path_planner/autoware_behavior_path_planner_common/include/autoware/behavior_path_planner_common/interface/scene_module_interface.hpp @@ -21,11 +21,11 @@ #include "autoware/behavior_path_planner_common/utils/utils.hpp" #include -#include #include #include #include #include +#include #include #include #include @@ -52,9 +52,9 @@ namespace autoware::behavior_path_planner { -using autoware::motion_utils::PlanningFactorInterface; using autoware::objects_of_interest_marker_interface::ColorName; using autoware::objects_of_interest_marker_interface::ObjectsOfInterestMarkerInterface; +using autoware::planning_factor_interface::PlanningFactorInterface; using autoware::rtc_interface::RTCInterface; using autoware::universe_utils::calcOffsetPose; using autoware::universe_utils::generateUUID; diff --git a/planning/behavior_path_planner/autoware_behavior_path_planner_common/package.xml b/planning/behavior_path_planner/autoware_behavior_path_planner_common/package.xml index f23a9980f1237..22237a5a1d3a4 100644 --- a/planning/behavior_path_planner/autoware_behavior_path_planner_common/package.xml +++ b/planning/behavior_path_planner/autoware_behavior_path_planner_common/package.xml @@ -52,6 +52,7 @@ autoware_object_recognition_utils autoware_objects_of_interest_marker_interface autoware_perception_msgs + autoware_planning_factor_interface autoware_planning_msgs autoware_route_handler autoware_rtc_interface diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp index 91eff0b01346a..2d7b79357b602 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/include/autoware/behavior_velocity_blind_spot_module/scene.hpp @@ -76,7 +76,8 @@ class BlindSpotModule : public SceneModuleInterfaceWithRTC const std::shared_ptr planner_data, const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); /** * @brief plan go-stop velocity at traffic crossing with collision check between reference path diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp index 4fca5f821f934..12943912f04cd 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_blind_spot_module/src/scene.cpp @@ -42,7 +42,8 @@ BlindSpotModule::BlindSpotModule( const std::shared_ptr planner_data, const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), planner_param_{planner_param}, diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp index 844647e33f8c0..754c14df9fac7 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp @@ -177,7 +177,8 @@ CrosswalkModule::CrosswalkModule( const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), module_id_(module_id), planner_param_(planner_param), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp index f32ee96623822..b9803207a1a31 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp @@ -336,7 +336,8 @@ class CrosswalkModule : public SceneModuleInterfaceWithRTC const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp index 7e6a320f3ddad..8641ce19e4ae5 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.cpp @@ -38,7 +38,8 @@ DetectionAreaModule::DetectionAreaModule( const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), detection_area_reg_elem_(detection_area_reg_elem), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp index 1d3e5f3540ff3..42cc0461cd59d 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_detection_area_module/src/scene.hpp @@ -70,7 +70,8 @@ class DetectionAreaModule : public SceneModuleInterface const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp index 5b8aca1c8ec9d..daebfbed3d12a 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.cpp @@ -51,7 +51,8 @@ IntersectionModule::IntersectionModule( const std::string & turn_direction, const bool has_traffic_light, rclcpp::Node & node, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), planner_param_(planner_param), lane_id_(lane_id), @@ -702,7 +703,7 @@ void reactRTCApprovalByDecisionResult( [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, [[maybe_unused]] const double baselink2front, [[maybe_unused]] tier4_planning_msgs::msg::PathWithLaneId * path, - [[maybe_unused]] motion_utils::PlanningFactorInterface * planning_factor_interface, + [[maybe_unused]] planning_factor_interface::PlanningFactorInterface * planning_factor_interface, [[maybe_unused]] IntersectionModule::DebugData * debug_data) { static_assert("Unsupported type passed to reactRTCByDecisionResult"); @@ -717,7 +718,7 @@ void reactRTCApprovalByDecisionResult( [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, [[maybe_unused]] const double baselink2front, [[maybe_unused]] tier4_planning_msgs::msg::PathWithLaneId * path, - [[maybe_unused]] motion_utils::PlanningFactorInterface * planning_factor_interface, + [[maybe_unused]] planning_factor_interface::PlanningFactorInterface * planning_factor_interface, [[maybe_unused]] IntersectionModule::DebugData * debug_data) { return; @@ -731,7 +732,7 @@ void reactRTCApprovalByDecisionResult( [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, [[maybe_unused]] const double baselink2front, [[maybe_unused]] tier4_planning_msgs::msg::PathWithLaneId * path, - [[maybe_unused]] motion_utils::PlanningFactorInterface * planning_factor_interface, + [[maybe_unused]] planning_factor_interface::PlanningFactorInterface * planning_factor_interface, [[maybe_unused]] IntersectionModule::DebugData * debug_data) { return; @@ -743,7 +744,7 @@ void reactRTCApprovalByDecisionResult( const StuckStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -790,7 +791,7 @@ void reactRTCApprovalByDecisionResult( const YieldStuckStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -822,7 +823,7 @@ void reactRTCApprovalByDecisionResult( const NonOccludedCollisionStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -866,7 +867,7 @@ void reactRTCApprovalByDecisionResult( const FirstWaitBeforeOcclusion & decision_result, const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -918,7 +919,7 @@ void reactRTCApprovalByDecisionResult( const PeekingTowardOcclusion & decision_result, const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -976,7 +977,7 @@ void reactRTCApprovalByDecisionResult( const OccludedCollisionStop & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -1024,7 +1025,7 @@ void reactRTCApprovalByDecisionResult( const OccludedAbsenceTrafficLight & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -1078,7 +1079,7 @@ void reactRTCApprovalByDecisionResult( const bool rtc_default_approved, const bool rtc_occlusion_approved, const Safe & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( @@ -1121,7 +1122,7 @@ void reactRTCApprovalByDecisionResult( const FullyPrioritized & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, const double baselink2front, tier4_planning_msgs::msg::PathWithLaneId * path, - motion_utils::PlanningFactorInterface * planning_factor_interface, + planning_factor_interface::PlanningFactorInterface * planning_factor_interface, IntersectionModule::DebugData * debug_data) { RCLCPP_DEBUG( diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp index db0cfbe98d53c..39a56977b301e 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_intersection.hpp @@ -306,7 +306,8 @@ class IntersectionModule : public SceneModuleInterfaceWithRTC const std::string & turn_direction, const bool has_traffic_light, rclcpp::Node & node, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); /** *********************************************************** diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp index fc442337198af..d12b58a63e531 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.cpp @@ -43,7 +43,8 @@ MergeFromPrivateRoadModule::MergeFromPrivateRoadModule( const PlannerParam & planner_param, const std::set & associative_ids, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), associative_ids_(associative_ids) diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp index fe446d304d9e0..4b9c0a9c5547e 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_intersection_module/src/scene_merge_from_private_road.hpp @@ -63,7 +63,8 @@ class MergeFromPrivateRoadModule : public SceneModuleInterface const PlannerParam & planner_param, const std::set & associative_ids, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); /** * @brief plan go-stop velocity at traffic crossing with collision check between reference path diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp index 0e646e92035cf..bbca1bf2d6481 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.cpp @@ -31,7 +31,8 @@ NoDrivableLaneModule::NoDrivableLaneModule( const int64_t module_id, const int64_t lane_id, const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), planner_param_(planner_param), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp index 835e946443e90..5490a37c7ec79 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_drivable_lane_module/src/scene.hpp @@ -57,7 +57,8 @@ class NoDrivableLaneModule : public SceneModuleInterface const int64_t module_id, const int64_t lane_id, const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp index c788a54073ed6..14f4f7b62c1f7 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.cpp @@ -43,7 +43,8 @@ NoStoppingAreaModule::NoStoppingAreaModule( const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterfaceWithRTC(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), no_stopping_area_reg_elem_(no_stopping_area_reg_elem), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp index 0d53441924805..036b6e30509c4 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_no_stopping_area_module/src/scene_no_stopping_area.hpp @@ -59,7 +59,8 @@ class NoStoppingAreaModule : public SceneModuleInterfaceWithRTC const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp index fa259b2bea9aa..935b1ec125024 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.cpp @@ -66,7 +66,8 @@ OcclusionSpotModule::OcclusionSpotModule( const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), param_(planner_param) { diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp index 22b2a91be66b0..c744cdcb22b84 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_occlusion_spot_module/src/scene_occlusion_spot.hpp @@ -50,7 +50,8 @@ class OcclusionSpotModule : public SceneModuleInterface const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); /** * @brief plan occlusion spot velocity at unknown area in occupancy grid diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp index 5bff3ca343e72..743fd0e31e387 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/include/autoware/behavior_velocity_planner_common/scene_module_interface.hpp @@ -17,10 +17,10 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -77,7 +77,8 @@ class SceneModuleInterface explicit SceneModuleInterface( const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); virtual ~SceneModuleInterface() = default; virtual bool modifyPathVelocity(PathWithLaneId * path) = 0; @@ -102,7 +103,7 @@ class SceneModuleInterface std::shared_ptr planner_data_; std::vector objects_of_interest_; mutable std::shared_ptr time_keeper_; - std::shared_ptr planning_factor_interface_; + std::shared_ptr planning_factor_interface_; void setObjectsOfInterestData( const geometry_msgs::msg::Pose & pose, const autoware_perception_msgs::msg::Shape & shape, @@ -136,7 +137,7 @@ class SceneModuleManagerInterface pub_virtual_wall_ = node.create_publisher( std::string("~/virtual_wall/") + module_name, 5); planning_factor_interface_ = - std::make_shared(&node, module_name); + std::make_shared(&node, module_name); processing_time_publisher_ = std::make_shared(&node, "~/debug"); @@ -261,7 +262,7 @@ class SceneModuleManagerInterface std::shared_ptr time_keeper_; - std::shared_ptr planning_factor_interface_; + std::shared_ptr planning_factor_interface_; }; extern template SceneModuleManagerInterface::SceneModuleManagerInterface( rclcpp::Node & node, [[maybe_unused]] const char * module_name); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/package.xml b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/package.xml index 9f920dff8f166..bf2a9dfc5e32e 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/package.xml +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/package.xml @@ -27,6 +27,7 @@ autoware_motion_utils autoware_objects_of_interest_marker_interface autoware_perception_msgs + autoware_planning_factor_interface autoware_planning_msgs autoware_route_handler autoware_universe_utils diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp index db2a274272f9f..1849c05085ac4 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_planner_common/src/scene_module_interface.cpp @@ -27,7 +27,8 @@ namespace autoware::behavior_velocity_planner SceneModuleInterface::SceneModuleInterface( const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : module_id_(module_id), logger_(logger), clock_(clock), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp index a955538f4f9fe..0cf1e343fb646 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/include/autoware/behavior_velocity_rtc_interface/scene_module_interface_with_rtc.hpp @@ -54,7 +54,8 @@ class SceneModuleInterfaceWithRTC : public SceneModuleInterface explicit SceneModuleInterfaceWithRTC( const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); virtual ~SceneModuleInterfaceWithRTC() = default; void setActivation(const bool activated) { activated_ = activated; } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/package.xml b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/package.xml index 88b252106a90a..3c2a229cca95a 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/package.xml +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/package.xml @@ -21,6 +21,7 @@ autoware_behavior_velocity_planner_common autoware_motion_utils + autoware_planning_factor_interface autoware_planning_msgs autoware_rtc_interface autoware_universe_utils diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp index 2e73b35e20ed9..34c7a30e73acf 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_rtc_interface/src/scene_module_interface_with_rtc.cpp @@ -29,7 +29,8 @@ namespace autoware::behavior_velocity_planner SceneModuleInterfaceWithRTC::SceneModuleInterfaceWithRTC( const int64_t module_id, rclcpp::Logger logger, rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), activated_(false), safe_(false), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp index 193ba5eab0553..a300e8f5f9284 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.cpp @@ -47,7 +47,8 @@ RunOutModule::RunOutModule( std::unique_ptr dynamic_obstacle_creator, const std::shared_ptr & debug_ptr, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), planner_param_(planner_param), dynamic_obstacle_creator_(std::move(dynamic_obstacle_creator)), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp index 49de16753a869..1879d724f98b3 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_run_out_module/src/scene.hpp @@ -49,7 +49,8 @@ class RunOutModule : public SceneModuleInterface std::unique_ptr dynamic_obstacle_creator, const std::shared_ptr & debug_ptr, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp index 4af7801e50ba3..a5099eedce027 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.cpp @@ -36,7 +36,8 @@ SpeedBumpModule::SpeedBumpModule( const lanelet::autoware::SpeedBump & speed_bump_reg_elem, const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), module_id_(module_id), lane_id_(lane_id), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp index e3ee2c0566381..5b908f90bf9c2 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_speed_bump_module/src/scene.hpp @@ -57,7 +57,8 @@ class SpeedBumpModule : public SceneModuleInterface const lanelet::autoware::SpeedBump & speed_bump_reg_elem, const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp index e2ddbc75c7b57..2115a0a7eca6e 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.cpp @@ -31,7 +31,8 @@ StopLineModule::StopLineModule( const int64_t module_id, lanelet::ConstLineString3d stop_line, const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), stop_line_(std::move(stop_line)), planner_param_(planner_param), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp index 7d430463c18b9..d2c999a377ab4 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/src/scene.hpp @@ -70,7 +70,8 @@ class StopLineModule : public SceneModuleInterface const PlannerParam & planner_param, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp index e304b479a005d..2b176a64c597d 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_stop_line_module/test/test_scene.cpp @@ -76,7 +76,7 @@ class StopLineModuleTest : public ::testing::Test module_ = std::make_shared( 1, stop_line_, planner_param_, rclcpp::get_logger("test_logger"), clock_, std::make_shared(), - std::make_shared( + std::make_shared( node_.get(), "test_stopline")); module_->setPlannerData(planner_data_); diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp index d8eea337e7186..7dc8ca9b2e43b 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.cpp @@ -28,7 +28,8 @@ namespace autoware::behavior_velocity_planner TemplateModule::TemplateModule( const int64_t module_id, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface) { } diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp index ba078f3fd6421..d204e589f0416 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_template_module/src/scene.hpp @@ -31,7 +31,8 @@ class TemplateModule : public SceneModuleInterface TemplateModule( const int64_t module_id, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); /** * @brief Modify the velocity of path points. diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp index becbaf5ee05f2..3a8692e9c53dd 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.cpp @@ -45,7 +45,8 @@ TrafficLightModule::TrafficLightModule( lanelet::ConstLanelet lane, const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterfaceWithRTC(lane_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), traffic_light_reg_elem_(traffic_light_reg_elem), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp index c30cbbdfc1477..71f0855a4af6f 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_traffic_light_module/src/scene.hpp @@ -71,7 +71,8 @@ class TrafficLightModule : public SceneModuleInterfaceWithRTC lanelet::ConstLanelet lane, const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp index a5779cfc0712a..a42e3520ea3c1 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.cpp @@ -41,7 +41,8 @@ VirtualTrafficLightModule::VirtualTrafficLightModule( const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), lane_id_(lane_id), reg_elem_(reg_elem), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp index 0661267b3d361..24e77cfaea157 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_virtual_traffic_light_module/src/scene.hpp @@ -84,7 +84,8 @@ class VirtualTrafficLightModule : public SceneModuleInterface const PlannerParam & planner_param, const rclcpp::Logger logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp index 94421ae27e077..91ed11a7467d5 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.cpp @@ -35,7 +35,8 @@ WalkwayModule::WalkwayModule( const PlannerParam & planner_param, const bool use_regulatory_element, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface) + const std::shared_ptr + planning_factor_interface) : SceneModuleInterface(module_id, logger, clock, time_keeper, planning_factor_interface), module_id_(module_id), state_(State::APPROACH), diff --git a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp index 1bd5003498d34..3e06bf2d878c6 100644 --- a/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp +++ b/planning/behavior_velocity_planner/autoware_behavior_velocity_walkway_module/src/scene_walkway.hpp @@ -46,7 +46,8 @@ class WalkwayModule : public SceneModuleInterface const PlannerParam & planner_param, const bool use_regulatory_element, const rclcpp::Logger & logger, const rclcpp::Clock::SharedPtr clock, const std::shared_ptr time_keeper, - const std::shared_ptr planning_factor_interface); + const std::shared_ptr + planning_factor_interface); bool modifyPathVelocity(PathWithLaneId * path) override; diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp index 2000615b51e2c..c7a103e0269ca 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_dynamic_obstacle_stop_module/src/dynamic_obstacle_stop_module.cpp @@ -44,8 +44,9 @@ void DynamicObstacleStopModule::init(rclcpp::Node & node, const std::string & mo logger_ = node.get_logger().get_child(ns_); clock_ = node.get_clock(); - planning_factor_interface_ = std::make_unique( - &node, "dynamic_obstacle_stop"); + planning_factor_interface_ = + std::make_unique( + &node, "dynamic_obstacle_stop"); debug_publisher_ = node.create_publisher("~/" + ns_ + "/debug_markers", 1); diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp b/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp index 532cc1e8c7d51..ab69218ea9668 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_out_of_lane_module/src/out_of_lane_module.cpp @@ -60,7 +60,8 @@ void OutOfLaneModule::init(rclcpp::Node & node, const std::string & module_name) init_parameters(node); planning_factor_interface_ = - std::make_unique(&node, "out_of_lane"); + std::make_unique( + &node, "out_of_lane"); debug_publisher_ = node.create_publisher("~/" + ns_ + "/debug_markers", 1); diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp b/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp index 6d683acff667f..c650e324de16a 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_common/include/autoware/motion_velocity_planner_common/plugin_module_interface.hpp @@ -18,7 +18,7 @@ #include "planner_data.hpp" #include "velocity_planning_result.hpp" -#include +#include #include #include @@ -55,7 +55,8 @@ class PluginModuleInterface autoware::motion_utils::VirtualWallMarkerCreator virtual_wall_marker_creator{}; protected: - std::unique_ptr planning_factor_interface_; + std::unique_ptr + planning_factor_interface_; }; } // namespace autoware::motion_velocity_planner diff --git a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/package.xml b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/package.xml index 07b719689f51f..5f4c15e0f8ab9 100644 --- a/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/package.xml +++ b/planning/motion_velocity_planner/autoware_motion_velocity_planner_node/package.xml @@ -23,6 +23,7 @@ autoware_motion_utils autoware_motion_velocity_planner_common autoware_perception_msgs + autoware_planning_factor_interface autoware_planning_msgs autoware_universe_utils autoware_velocity_smoother From 62fa8ce18643ba44caaf5016fc4f4ff1e8365cd7 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:16:01 +0900 Subject: [PATCH 59/61] feat(autoware_planning_validator)!: tier4_debug_msgs changed to autoware_internal_debug_msgs in autoware_planning_validator (#9911) feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files planning/autoware_planning_validator Signed-off-by: vish0012 --- .../autoware/planning_validator/planning_validator.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/planning/autoware_planning_validator/include/autoware/planning_validator/planning_validator.hpp b/planning/autoware_planning_validator/include/autoware/planning_validator/planning_validator.hpp index e996855b9b4da..298e7f74c289b 100644 --- a/planning/autoware_planning_validator/include/autoware/planning_validator/planning_validator.hpp +++ b/planning/autoware_planning_validator/include/autoware/planning_validator/planning_validator.hpp @@ -26,10 +26,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -37,13 +37,13 @@ namespace autoware::planning_validator { using autoware::universe_utils::StopWatch; +using autoware_internal_debug_msgs::msg::Float64Stamped; using autoware_planning_msgs::msg::Trajectory; using autoware_planning_msgs::msg::TrajectoryPoint; using autoware_planning_validator::msg::PlanningValidatorStatus; using diagnostic_updater::DiagnosticStatusWrapper; using diagnostic_updater::Updater; using nav_msgs::msg::Odometry; -using tier4_debug_msgs::msg::Float64Stamped; struct ValidationParams { From c926e46aaefbb37c1738cd7b20269a8e4dd602b8 Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:16:57 +0900 Subject: [PATCH 60/61] =?UTF-8?q?feat:=20tier4=5Fdebug=5Fmsgs=20changed=20?= =?UTF-8?q?to=20autoware=5Finternal=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(?= =?UTF-8?q?#9904)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files planning/autoware_mission_planner Signed-off-by: vish0012 --- .../src/mission_planner/mission_planner.cpp | 6 +++--- .../src/mission_planner/mission_planner.hpp | 5 +++-- .../src/mission_planner/route_selector.cpp | 6 +++--- .../src/mission_planner/route_selector.hpp | 5 +++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/planning/autoware_mission_planner/src/mission_planner/mission_planner.cpp b/planning/autoware_mission_planner/src/mission_planner/mission_planner.cpp index cbbcfb84d2cbb..b806feded9802 100644 --- a/planning/autoware_mission_planner/src/mission_planner/mission_planner.cpp +++ b/planning/autoware_mission_planner/src/mission_planner/mission_planner.cpp @@ -87,14 +87,14 @@ MissionPlanner::MissionPlanner(const rclcpp::NodeOptions & options) is_mission_planner_ready_ = false; logger_configure_ = std::make_unique(this); - pub_processing_time_ = - this->create_publisher("~/debug/processing_time_ms", 1); + pub_processing_time_ = this->create_publisher( + "~/debug/processing_time_ms", 1); } void MissionPlanner::publish_processing_time( autoware::universe_utils::StopWatch stop_watch) { - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); pub_processing_time_->publish(processing_time_msg); diff --git a/planning/autoware_mission_planner/src/mission_planner/mission_planner.hpp b/planning/autoware_mission_planner/src/mission_planner/mission_planner.hpp index 987ca6482ec11..18f0d3a9c259d 100644 --- a/planning/autoware_mission_planner/src/mission_planner/mission_planner.hpp +++ b/planning/autoware_mission_planner/src/mission_planner/mission_planner.hpp @@ -28,9 +28,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -146,7 +146,8 @@ class MissionPlanner : public rclcpp::Node bool check_reroute_safety(const LaneletRoute & original_route, const LaneletRoute & target_route); std::unique_ptr logger_configure_; - rclcpp::Publisher::SharedPtr pub_processing_time_; + rclcpp::Publisher::SharedPtr + pub_processing_time_; }; } // namespace autoware::mission_planner diff --git a/planning/autoware_mission_planner/src/mission_planner/route_selector.cpp b/planning/autoware_mission_planner/src/mission_planner/route_selector.cpp index 5ee565af00423..ad7daba18dece 100644 --- a/planning/autoware_mission_planner/src/mission_planner/route_selector.cpp +++ b/planning/autoware_mission_planner/src/mission_planner/route_selector.cpp @@ -138,14 +138,14 @@ RouteSelector::RouteSelector(const rclcpp::NodeOptions & options) main_request_ = std::monostate{}; // Processing time - pub_processing_time_ = - this->create_publisher("~/debug/processing_time_ms", 1); + pub_processing_time_ = this->create_publisher( + "~/debug/processing_time_ms", 1); } void RouteSelector::publish_processing_time( autoware::universe_utils::StopWatch stop_watch) { - tier4_debug_msgs::msg::Float64Stamped processing_time_msg; + autoware_internal_debug_msgs::msg::Float64Stamped processing_time_msg; processing_time_msg.stamp = get_clock()->now(); processing_time_msg.data = stop_watch.toc(); pub_processing_time_->publish(processing_time_msg); diff --git a/planning/autoware_mission_planner/src/mission_planner/route_selector.hpp b/planning/autoware_mission_planner/src/mission_planner/route_selector.hpp index 5c8f81aaf216e..3e52f6962c47e 100644 --- a/planning/autoware_mission_planner/src/mission_planner/route_selector.hpp +++ b/planning/autoware_mission_planner/src/mission_planner/route_selector.hpp @@ -18,8 +18,8 @@ #include #include +#include #include -#include #include #include #include @@ -82,7 +82,8 @@ class RouteSelector : public rclcpp::Node rclcpp::Client::SharedPtr cli_set_lanelet_route_; rclcpp::Subscription::SharedPtr sub_state_; rclcpp::Subscription::SharedPtr sub_route_; - rclcpp::Publisher::SharedPtr pub_processing_time_; + rclcpp::Publisher::SharedPtr + pub_processing_time_; bool initialized_; bool mrm_operating_; From b466796bbe9464e191f31e1e3a885f7025fad11f Mon Sep 17 00:00:00 2001 From: Vishal Chauhan <40782713+vish0012@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:17:26 +0900 Subject: [PATCH 61/61] =?UTF-8?q?feat:=20tier4=5Fdebug=5Fmsgs=20changed=20?= =?UTF-8?q?to=20autoware=5Finternal=5Fdebug=5Fmsgs=20in=20fil=E2=80=A6=20(?= =?UTF-8?q?#9902)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: tier4_debug_msgs changed to autoware_internal_debug_msgs in files planning/autoware_external_velocity_limit_selector Signed-off-by: vish0012 --- .../external_velocity_limit_selector_node.hpp | 4 ++-- .../autoware_external_velocity_limit_selector/package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/planning/autoware_external_velocity_limit_selector/include/autoware/external_velocity_limit_selector/external_velocity_limit_selector_node.hpp b/planning/autoware_external_velocity_limit_selector/include/autoware/external_velocity_limit_selector/external_velocity_limit_selector_node.hpp index 6a8fae3bf394c..be4893d5a49c6 100644 --- a/planning/autoware_external_velocity_limit_selector/include/autoware/external_velocity_limit_selector/external_velocity_limit_selector_node.hpp +++ b/planning/autoware_external_velocity_limit_selector/include/autoware/external_velocity_limit_selector/external_velocity_limit_selector_node.hpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ namespace autoware::external_velocity_limit_selector { -using tier4_debug_msgs::msg::StringStamped; +using autoware_internal_debug_msgs::msg::StringStamped; using tier4_planning_msgs::msg::VelocityLimit; using tier4_planning_msgs::msg::VelocityLimitClearCommand; using tier4_planning_msgs::msg::VelocityLimitConstraints; diff --git a/planning/autoware_external_velocity_limit_selector/package.xml b/planning/autoware_external_velocity_limit_selector/package.xml index 5bfd3fa936d50..4a4fac40bd8a5 100644 --- a/planning/autoware_external_velocity_limit_selector/package.xml +++ b/planning/autoware_external_velocity_limit_selector/package.xml @@ -17,10 +17,10 @@ ament_cmake_auto autoware_cmake + autoware_internal_debug_msgs generate_parameter_library rclcpp rclcpp_components - tier4_debug_msgs tier4_planning_msgs ros2cli