From 9fb03ac1878d810e2b554476706cb091ee2c558f Mon Sep 17 00:00:00 2001 From: Zulfaqar Azmi <93502286+zulfaqar-azmi-t4@users.noreply.github.com> Date: Wed, 24 Jan 2024 18:01:57 +0900 Subject: [PATCH 001/132] refactor(lane_change): update lc status in updateData (#6088) * refactor(lane_change): update lc status in updateData Signed-off-by: Muhammad Zulfaqar Azmi * update current lane and target lane during requested Signed-off-by: Muhammad Zulfaqar Azmi * set is_valid_path as false by default Signed-off-by: Muhammad Zulfaqar Azmi * reset flags after finished lane change Signed-off-by: Muhammad Zulfaqar Azmi --------- Signed-off-by: Muhammad Zulfaqar Azmi --- .../scene.hpp | 2 +- .../utils/base_class.hpp | 2 +- .../utils/path.hpp | 2 +- .../src/interface.cpp | 24 ++++++++----------- .../src/scene.cpp | 17 +++++++++---- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp index 9c3c371627a78..f991ca0d849f0 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp @@ -89,7 +89,7 @@ class NormalLaneChange : public LaneChangeBase bool isAbortState() const override; - bool isLaneChangeRequired() const override; + bool isLaneChangeRequired() override; bool isStoppedAtRedTrafficLight() const override; diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp index 451899fbf27e6..400d5505dc49f 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp @@ -80,7 +80,7 @@ class LaneChangeBase virtual bool hasFinishedAbort() const = 0; - virtual bool isLaneChangeRequired() const = 0; + virtual bool isLaneChangeRequired() = 0; virtual bool isAbortState() const = 0; diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/path.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/path.hpp index 9e42b49635b82..3af4f487a0fa0 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/path.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/path.hpp @@ -45,7 +45,7 @@ struct LaneChangeStatus std::vector lane_follow_lane_ids{}; std::vector lane_change_lane_ids{}; bool is_safe{false}; - bool is_valid_path{true}; + bool is_valid_path{false}; double start_distance{0.0}; }; diff --git a/planning/behavior_path_lane_change_module/src/interface.cpp b/planning/behavior_path_lane_change_module/src/interface.cpp index 448f83ecaf15e..c8e1229fe5af5 100644 --- a/planning/behavior_path_lane_change_module/src/interface.cpp +++ b/planning/behavior_path_lane_change_module/src/interface.cpp @@ -50,9 +50,6 @@ LaneChangeInterface::LaneChangeInterface( void LaneChangeInterface::processOnEntry() { waitApproval(); - module_type_->setPreviousModulePaths( - getPreviousModuleOutput().reference_path, getPreviousModuleOutput().path); - module_type_->updateLaneChangeStatus(); } void LaneChangeInterface::processOnExit() @@ -80,6 +77,14 @@ void LaneChangeInterface::updateData() { module_type_->setPreviousModulePaths( getPreviousModuleOutput().reference_path, getPreviousModuleOutput().path); + module_type_->setPreviousDrivableAreaInfo(getPreviousModuleOutput().drivable_area_info); + module_type_->setPreviousTurnSignalInfo(getPreviousModuleOutput().turn_signal_info); + + if (isWaitingApproval()) { + module_type_->updateLaneChangeStatus(); + } + setObjectDebugVisualization(); + module_type_->updateSpecialData(); module_type_->resetStopPose(); } @@ -98,8 +103,6 @@ BehaviorModuleOutput LaneChangeInterface::plan() return {}; } - module_type_->setPreviousDrivableAreaInfo(getPreviousModuleOutput().drivable_area_info); - module_type_->setPreviousTurnSignalInfo(getPreviousModuleOutput().turn_signal_info); auto output = module_type_->generateOutput(); path_reference_ = std::make_shared(output.reference_path); *prev_approved_path_ = getPreviousModuleOutput().path; @@ -128,22 +131,14 @@ BehaviorModuleOutput LaneChangeInterface::planWaitingApproval() out.reference_path = getPreviousModuleOutput().reference_path; out.turn_signal_info = getPreviousModuleOutput().turn_signal_info; out.drivable_area_info = getPreviousModuleOutput().drivable_area_info; - - module_type_->setPreviousModulePaths( - getPreviousModuleOutput().reference_path, getPreviousModuleOutput().path); - module_type_->updateLaneChangeStatus(); - setObjectDebugVisualization(); + out.turn_signal_info = getCurrentTurnSignalInfo(out.path, out.turn_signal_info); for (const auto & [uuid, data] : module_type_->getDebugData()) { const auto color = data.is_safe ? ColorName::GREEN : ColorName::RED; setObjectsOfInterestData(data.current_obj_pose, data.obj_shape, color); } - // change turn signal when the vehicle reaches at the end of the path for waiting lane change - out.turn_signal_info = getCurrentTurnSignalInfo(out.path, out.turn_signal_info); - path_reference_ = std::make_shared(getPreviousModuleOutput().reference_path); - stop_pose_ = module_type_->getStopPose(); if (!module_type_->isValidPath()) { @@ -211,6 +206,7 @@ bool LaneChangeInterface::canTransitSuccessState() } if (module_type_->hasFinishedLaneChange()) { + module_type_->resetParameters(); log_debug_throttled("Lane change process has completed."); return true; } diff --git a/planning/behavior_path_lane_change_module/src/scene.cpp b/planning/behavior_path_lane_change_module/src/scene.cpp index c7ddd8fe63636..f5100f16129c2 100644 --- a/planning/behavior_path_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_lane_change_module/src/scene.cpp @@ -115,17 +115,17 @@ std::pair NormalLaneChange::getSafePath(LaneChangePath & safe_path) return {true, found_safe_path}; } -bool NormalLaneChange::isLaneChangeRequired() const +bool NormalLaneChange::isLaneChangeRequired() { - const auto current_lanes = getCurrentLanes(); + status_.current_lanes = getCurrentLanes(); - if (current_lanes.empty()) { + if (status_.current_lanes.empty()) { return false; } - const auto target_lanes = getLaneChangeLanes(current_lanes, direction_); + status_.target_lanes = getLaneChangeLanes(status_.current_lanes, direction_); - return !target_lanes.empty(); + return !status_.target_lanes.empty(); } bool NormalLaneChange::isStoppedAtRedTrafficLight() const @@ -420,8 +420,15 @@ void NormalLaneChange::resetParameters() is_abort_approval_requested_ = false; current_lane_change_state_ = LaneChangeStates::Normal; abort_path_ = nullptr; + status_ = {}; object_debug_.clear(); + object_debug_after_approval_.clear(); + debug_filtered_objects_.current_lane.clear(); + debug_filtered_objects_.target_lane.clear(); + debug_filtered_objects_.other_lane.clear(); + debug_valid_path_.clear(); + RCLCPP_DEBUG(logger_, "reset all flags and debug information."); } TurnSignalInfo NormalLaneChange::updateOutputTurnSignal() From 51a5f22c1cf15cb688b3591e76f11cc23d772e42 Mon Sep 17 00:00:00 2001 From: Yamato Ando Date: Wed, 24 Jan 2024 18:54:10 +0900 Subject: [PATCH 002/132] docs(map_projection_loader): add limitations (#6140) * docs(map_projection_loader): add limitations Signed-off-by: Yamato Ando * style(pre-commit): autofix --------- Signed-off-by: Yamato Ando Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- map/map_projection_loader/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/map/map_projection_loader/README.md b/map/map_projection_loader/README.md index 94b142da3dcf9..1887a1cd8934f 100644 --- a/map/map_projection_loader/README.md +++ b/map/map_projection_loader/README.md @@ -28,6 +28,15 @@ sample-map-rosbag projector_type: local ``` +#### Limitation + +The functionality that requires latitude and longitude will become unavailable. + +The currently identified unavailable functionalities are: + +- GNSS localization +- Sending the self-position in latitude and longitude using ADAPI + ### Using MGRS If you want to use MGRS, please specify the MGRS grid as well. @@ -39,6 +48,10 @@ vertical_datum: WGS84 mgrs_grid: 54SUE ``` +#### Limitation + +It cannot be used with maps that span across two or more MGRS grids. Please use it only when it falls within the scope of a single MGRS grid. + ### Using LocalCartesianUTM If you want to use local cartesian UTM, please specify the map origin as well. From 3b9bd421e486405fc26a5a606e79069446ac4ca4 Mon Sep 17 00:00:00 2001 From: Kento Yabuuchi Date: Wed, 24 Jan 2024 19:08:13 +0900 Subject: [PATCH 003/132] fix(gnss_poser): remove gnss_frame from schema.json (#6155) remove gnss_frame from gnss_poser.schema.json Signed-off-by: Kento Yabuuchi --- sensing/gnss_poser/schema/gnss_poser.schema.json | 1 - 1 file changed, 1 deletion(-) diff --git a/sensing/gnss_poser/schema/gnss_poser.schema.json b/sensing/gnss_poser/schema/gnss_poser.schema.json index 6d9bc716e121a..d6e104b7432f2 100644 --- a/sensing/gnss_poser/schema/gnss_poser.schema.json +++ b/sensing/gnss_poser/schema/gnss_poser.schema.json @@ -42,7 +42,6 @@ }, "required": [ "base_frame", - "gnss_frame", "gnss_base_frame", "map_frame", "use_gnss_ins_orientation", From b5896a3c9ee751aede8eb04b903d469c14e8408c Mon Sep 17 00:00:00 2001 From: Tao Zhong <55872497+tzhong518@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:13:46 +0900 Subject: [PATCH 004/132] revert(perf_ring_outlier_filter): temporal revert for further investigation (#6148) Revert "perf(ring_outlier_filter): a cache friendly impl (continuation of VRichardJP's work) (#4185)" This reverts commit e45c1ce8df336aef408650532b0477dd174ae27d. --- .../docs/ring-outlier-filter.md | 13 +- .../ring_outlier_filter_nodelet.hpp | 16 + sensing/pointcloud_preprocessor/package.xml | 1 - .../ring_outlier_filter_nodelet.cpp | 342 +++++------------- 4 files changed, 123 insertions(+), 249 deletions(-) diff --git a/sensing/pointcloud_preprocessor/docs/ring-outlier-filter.md b/sensing/pointcloud_preprocessor/docs/ring-outlier-filter.md index eedc8e6bcb573..42ca694235a00 100644 --- a/sensing/pointcloud_preprocessor/docs/ring-outlier-filter.md +++ b/sensing/pointcloud_preprocessor/docs/ring-outlier-filter.md @@ -22,12 +22,13 @@ This implementation inherits `pointcloud_preprocessor::Filter` class, please ref ### Core Parameters -| Name | Type | Default Value | Description | -| ------------------------- | ------- | ------------- | ----------- | -| `distance_ratio` | double | 1.03 | | -| `object_length_threshold` | double | 0.1 | | -| `num_points_threshold` | int | 4 | | -| `max_rings_num` | uint_16 | 128 | | +| Name | Type | Default Value | Description | +| ------------------------- | ------- | ------------- | ----------------------------------------------------------------------------------- | +| `distance_ratio` | double | 1.03 | | +| `object_length_threshold` | double | 0.1 | | +| `num_points_threshold` | int | 4 | | +| `max_rings_num` | uint_16 | 128 | | +| `max_points_num_per_ring` | size_t | 4000 | Set this value large enough such that `HFoV / resolution < max_points_num_per_ring` | ## Assumptions / Known limits diff --git a/sensing/pointcloud_preprocessor/include/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_nodelet.hpp b/sensing/pointcloud_preprocessor/include/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_nodelet.hpp index f655a9245ca6d..ab7d4e0012304 100644 --- a/sensing/pointcloud_preprocessor/include/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_nodelet.hpp +++ b/sensing/pointcloud_preprocessor/include/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_nodelet.hpp @@ -46,6 +46,7 @@ class RingOutlierFilterComponent : public pointcloud_preprocessor::Filter double object_length_threshold_; int num_points_threshold_; uint16_t max_rings_num_; + size_t max_points_num_per_ring_; /** \brief Parameter service callback result : needed to be hold */ OnSetParametersCallbackHandle::SharedPtr set_param_res_; @@ -53,6 +54,21 @@ class RingOutlierFilterComponent : public pointcloud_preprocessor::Filter /** \brief Parameter service callback */ rcl_interfaces::msg::SetParametersResult paramCallback(const std::vector & p); + bool isCluster( + const PointCloud2ConstPtr & input, std::pair data_idx_both_ends, int walk_size) + { + if (walk_size > num_points_threshold_) return true; + + auto first_point = reinterpret_cast(&input->data[data_idx_both_ends.first]); + auto last_point = reinterpret_cast(&input->data[data_idx_both_ends.second]); + + const auto x = first_point->x - last_point->x; + const auto y = first_point->y - last_point->y; + const auto z = first_point->z - last_point->z; + + return x * x + y * y + z * z >= object_length_threshold_ * object_length_threshold_; + } + public: PCL_MAKE_ALIGNED_OPERATOR_NEW explicit RingOutlierFilterComponent(const rclcpp::NodeOptions & options); diff --git a/sensing/pointcloud_preprocessor/package.xml b/sensing/pointcloud_preprocessor/package.xml index e3090f34d6854..a65d14c0a1194 100644 --- a/sensing/pointcloud_preprocessor/package.xml +++ b/sensing/pointcloud_preprocessor/package.xml @@ -31,7 +31,6 @@ pcl_msgs pcl_ros point_cloud_msg_wrapper - range-v3 rclcpp rclcpp_components sensor_msgs diff --git a/sensing/pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_nodelet.cpp b/sensing/pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_nodelet.cpp index e277b221a090d..d2570b9c4d786 100644 --- a/sensing/pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_nodelet.cpp +++ b/sensing/pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_nodelet.cpp @@ -14,18 +14,10 @@ #include "pointcloud_preprocessor/outlier_filter/ring_outlier_filter_nodelet.hpp" -#include "pointcloud_preprocessor/utility/utilities.hpp" - -#include -#include -#include - #include #include -#include #include - namespace pointcloud_preprocessor { RingOutlierFilterComponent::RingOutlierFilterComponent(const rclcpp::NodeOptions & options) @@ -48,6 +40,8 @@ RingOutlierFilterComponent::RingOutlierFilterComponent(const rclcpp::NodeOptions static_cast(declare_parameter("object_length_threshold", 0.1)); num_points_threshold_ = static_cast(declare_parameter("num_points_threshold", 4)); max_rings_num_ = static_cast(declare_parameter("max_rings_num", 128)); + max_points_num_per_ring_ = + static_cast(declare_parameter("max_points_num_per_ring", 4000)); } using std::placeholders::_1; @@ -67,252 +61,122 @@ void RingOutlierFilterComponent::faster_filter( } stop_watch_ptr_->toc("processing_time", true); - // The ring_outlier_filter specifies the expected input point cloud format, - // however, we want to verify the input is correct and make failures explicit. - auto getFieldOffsetSafely = [=]( - const std::string & field_name, - const pcl::PCLPointField::PointFieldTypes expected_type) -> size_t { - const auto field_index = pcl::getFieldIndex(*input, field_name); - if (field_index == -1) { - RCLCPP_ERROR(get_logger(), "Field %s not found in input point cloud", field_name.c_str()); - return -1UL; - } - - auto field = (*input).fields.at(field_index); - if (field.datatype != expected_type) { - RCLCPP_ERROR( - get_logger(), "Field %s has unexpected type %d (expected %d)", field_name.c_str(), - field.datatype, expected_type); - return -1UL; - } - - return static_cast(field.offset); - }; + output.point_step = sizeof(PointXYZI); + output.data.resize(output.point_step * input->width); + size_t output_size = 0; - // as per the specification of this node, these fields must be present in the input - const auto ring_offset = getFieldOffsetSafely("ring", pcl::PCLPointField::UINT16); - const auto azimuth_offset = getFieldOffsetSafely("azimuth", pcl::PCLPointField::FLOAT32); - const auto distance_offset = getFieldOffsetSafely("distance", pcl::PCLPointField::FLOAT32); - const auto intensity_offset = getFieldOffsetSafely("intensity", pcl::PCLPointField::FLOAT32); + const auto ring_offset = + input->fields.at(static_cast(autoware_point_types::PointIndex::Ring)).offset; + const auto azimuth_offset = + input->fields.at(static_cast(autoware_point_types::PointIndex::Azimuth)).offset; + const auto distance_offset = + input->fields.at(static_cast(autoware_point_types::PointIndex::Distance)).offset; + const auto intensity_offset = + input->fields.at(static_cast(autoware_point_types::PointIndex::Intensity)).offset; + + std::vector> ring2indices; + ring2indices.reserve(max_rings_num_); + + for (uint16_t i = 0; i < max_rings_num_; i++) { + ring2indices.push_back(std::vector()); + ring2indices.back().reserve(max_points_num_per_ring_); + } - if ( - ring_offset == -1UL || azimuth_offset == -1UL || distance_offset == -1UL || - intensity_offset == -1UL) { - RCLCPP_ERROR(get_logger(), "One or more required fields are missing in input point cloud"); - return; + for (size_t data_idx = 0; data_idx < input->data.size(); data_idx += input->point_step) { + const uint16_t ring = *reinterpret_cast(&input->data[data_idx + ring_offset]); + ring2indices[ring].push_back(data_idx); } - // The initial implementation of ring outlier filter looked like this: - // 1. Iterate over the input cloud and group point indices by ring - // 2. For each ring: - // 2.1. iterate over the ring points, and group points belonging to the same "walk" - // 2.2. when a walk is closed, copy indexed points to the output cloud if the walk is long - // enough. - // - // Because LIDAR data is naturally "azimuth-major order" and not "ring-major order", such - // implementation is not cache friendly at all, and has negative impact on all the other nodes. - // - // To tackle this issue, the algorithm has been rewritten so that points would be accessed in - // order. To do so, all rings are being processing simultaneously instead of separately. The - // overall logic is still the same. - - // ad-hoc struct to store finished walks information (for isCluster()) - struct WalkInfo - { - size_t id; - int num_points; - float first_point_distance; - float first_point_azimuth; - float last_point_distance; - float last_point_azimuth; - }; - - // ad-hoc struct to keep track of each ring current walk - struct RingWalkInfo - { - WalkInfo first_walk; - WalkInfo current_walk; - }; - - // helper functions - - // check if walk is a valid cluster - const float object_length_threshold2 = object_length_threshold_ * object_length_threshold_; - auto isCluster = [=](const WalkInfo & walk_info) { - // A cluster is a walk which has many points or is long enough - if (walk_info.num_points > num_points_threshold_) return true; - - // Using the law of cosines, the distance between 2 points can be written as: - // |p2-p1|^2 = d1^2 + d2^2 - 2*d1*d2*cos(a) - // where d1 and d2 are the distance attribute of p1 and p2, and 'a' the azimuth diff between - // the 2 points. - const float dist2 = - walk_info.first_point_distance * walk_info.first_point_distance + - walk_info.last_point_distance * walk_info.last_point_distance - - 2 * walk_info.first_point_distance * walk_info.last_point_distance * - std::cos((walk_info.last_point_azimuth - walk_info.first_point_azimuth) * (M_PI / 18000.0)); - return dist2 > object_length_threshold2; - }; - - // check if 2 points belong to the same walk - auto isSameWalk = - [=](float curr_distance, float curr_azimuth, float prev_distance, float prev_azimuth) { - float azimuth_diff = curr_azimuth - prev_azimuth; - azimuth_diff = azimuth_diff < 0.f ? azimuth_diff + 36000.f : azimuth_diff; - return std::max(curr_distance, prev_distance) < - std::min(curr_distance, prev_distance) * distance_ratio_ && - azimuth_diff < 100.f; - }; - - // tmp vectors to keep track of walk/ring state while processing points in order (cache efficient) - std::vector rings; // info for each LiDAR ring - std::vector points_walk_id; // for each input point, the walk index associated with it - std::vector - walks_cluster_status; // for each generated walk, stores whether it is a cluster - - size_t latest_walk_id = -1UL; // ID given to the latest walk created - - // initialize each ring with two empty walks (first and current walk) - rings.resize(max_rings_num_, RingWalkInfo{{-1UL, 0, 0, 0, 0, 0}, {-1UL, 0, 0, 0, 0, 0}}); - // points are initially associated to no walk (-1UL) - points_walk_id.resize(input->width * input->height, -1UL); - walks_cluster_status.reserve( - max_rings_num_ * 2); // In the worst case, this could grow to the number of input points - - int invalid_ring_count = 0; - - // Build walks and classify points - for (const auto & [raw_p, point_walk_id] : - ranges::views::zip(input->data | ranges::views::chunk(input->point_step), points_walk_id)) { - uint16_t ring_idx{}; - float curr_azimuth{}; - float curr_distance{}; - std::memcpy(&ring_idx, &raw_p.data()[ring_offset], sizeof(ring_idx)); - std::memcpy(&curr_azimuth, &raw_p.data()[azimuth_offset], sizeof(curr_azimuth)); - std::memcpy(&curr_distance, &raw_p.data()[distance_offset], sizeof(curr_distance)); - - if (ring_idx >= max_rings_num_) { - // Either the data is corrupted or max_rings_num_ is not set correctly - // Note: point_walk_id == -1 so the point will be filtered out - ++invalid_ring_count; - continue; - } + // walk range: [walk_first_idx, walk_last_idx] + int walk_first_idx = 0; + int walk_last_idx = -1; - auto & ring = rings[ring_idx]; - if (ring.current_walk.id == -1UL) { - // first walk ever for this ring. It is both the first and current walk of the ring. - ring.first_walk = - WalkInfo{++latest_walk_id, 1, curr_distance, curr_azimuth, curr_distance, curr_azimuth}; - ring.current_walk = ring.first_walk; - point_walk_id = latest_walk_id; - continue; - } + for (const auto & indices : ring2indices) { + if (indices.size() < 2) continue; - auto & walk = ring.current_walk; - if (isSameWalk( - curr_distance, curr_azimuth, walk.last_point_distance, walk.last_point_azimuth)) { - // current point is part of previous walk - walk.num_points += 1; - walk.last_point_distance = curr_distance; - walk.last_point_azimuth = curr_azimuth; - point_walk_id = walk.id; - } else { - // previous walk is finished, start a new one - - // check and store whether the previous walks is a cluster - if (walk.id >= walks_cluster_status.size()) walks_cluster_status.resize(walk.id + 1, false); - walks_cluster_status.at(walk.id) = isCluster(walk); - - ring.current_walk = - WalkInfo{++latest_walk_id, 1, curr_distance, curr_azimuth, curr_distance, curr_azimuth}; - point_walk_id = latest_walk_id; - } - } + walk_first_idx = 0; + walk_last_idx = -1; - // So far, we have processed ring points as if rings were not circular. Of course, the last and - // first points of a ring could totally be part of the same walk. When such thing happens, we need - // to merge the two walks - for (auto & ring : rings) { - if (ring.current_walk.id == -1UL) { - continue; - } + for (size_t idx = 0U; idx < indices.size() - 1; ++idx) { + const size_t & current_data_idx = indices[idx]; + const size_t & next_data_idx = indices[idx + 1]; + walk_last_idx = idx; - const auto & walk = ring.current_walk; - if (walk.id >= walks_cluster_status.size()) walks_cluster_status.resize(walk.id + 1, false); - walks_cluster_status.at(walk.id) = isCluster(walk); + // if(std::abs(iter->distance - (iter+1)->distance) <= std::sqrt(iter->distance) * 0.08) - if (ring.first_walk.id == ring.current_walk.id) { - continue; - } + const float & current_azimuth = + *reinterpret_cast(&input->data[current_data_idx + azimuth_offset]); + const float & next_azimuth = + *reinterpret_cast(&input->data[next_data_idx + azimuth_offset]); + float azimuth_diff = next_azimuth - current_azimuth; + azimuth_diff = azimuth_diff < 0.f ? azimuth_diff + 36000.f : azimuth_diff; - auto & first_walk = ring.first_walk; - auto & last_walk = ring.current_walk; - - // check if the two walks are connected - if (isSameWalk( - first_walk.first_point_distance, first_walk.first_point_azimuth, - last_walk.last_point_distance, last_walk.last_point_azimuth)) { - // merge - auto combined_num_points = first_walk.num_points + last_walk.num_points; - first_walk.first_point_distance = last_walk.first_point_distance; - first_walk.first_point_azimuth = last_walk.first_point_azimuth; - first_walk.num_points = combined_num_points; - last_walk.last_point_distance = first_walk.last_point_distance; - last_walk.last_point_azimuth = first_walk.last_point_azimuth; - last_walk.num_points = combined_num_points; - - walks_cluster_status.at(first_walk.id) = isCluster(first_walk); - walks_cluster_status.at(last_walk.id) = isCluster(last_walk); - } - } + const float & current_distance = + *reinterpret_cast(&input->data[current_data_idx + distance_offset]); + const float & next_distance = + *reinterpret_cast(&input->data[next_data_idx + distance_offset]); - // finally copy points - output.point_step = sizeof(PointXYZI); - output.data.resize(output.point_step * input->width * input->height); - size_t output_size = 0; - if (transform_info.need_transform) { - for (const auto & [raw_p, point_walk_id] : ranges::views::zip( - input->data | ranges::views::chunk(input->point_step), points_walk_id)) { - // Filter out points on invalid rings and points not in a cluster - if (point_walk_id == -1UL || !walks_cluster_status.at(point_walk_id)) { - continue; + if ( + std::max(current_distance, next_distance) < + std::min(current_distance, next_distance) * distance_ratio_ && + azimuth_diff < 100.f) { + continue; // Determined to be included in the same walk } - // assume binary representation of input point is compatible with PointXYZ* - PointXYZI out_point; - std::memcpy(&out_point, raw_p.data(), sizeof(PointXYZI)); - - Eigen::Vector4f p(out_point.x, out_point.y, out_point.z, 1); - p = transform_info.eigen_transform * p; - out_point.x = p[0]; - out_point.y = p[1]; - out_point.z = p[2]; - // FIXME(VRichardJP) tmp fix because input data does not have the same layout than PointXYZI - std::memcpy( - &out_point.intensity, &raw_p.data()[intensity_offset], sizeof(out_point.intensity)); - - std::memcpy(&output.data[output_size], &out_point, sizeof(PointXYZI)); - output_size += sizeof(PointXYZI); - } - } else { - for (const auto & [raw_p, point_walk_id] : ranges::views::zip( - input->data | ranges::views::chunk(input->point_step), points_walk_id)) { - // Filter out points on invalid rings and points not in a cluster - if (point_walk_id == -1UL || !walks_cluster_status.at(point_walk_id)) { - continue; + if (isCluster( + input, std::make_pair(indices[walk_first_idx], indices[walk_last_idx]), + walk_last_idx - walk_first_idx + 1)) { + for (int i = walk_first_idx; i <= walk_last_idx; i++) { + auto output_ptr = reinterpret_cast(&output.data[output_size]); + auto input_ptr = reinterpret_cast(&input->data[indices[i]]); + + if (transform_info.need_transform) { + Eigen::Vector4f p(input_ptr->x, input_ptr->y, input_ptr->z, 1); + p = transform_info.eigen_transform * p; + output_ptr->x = p[0]; + output_ptr->y = p[1]; + output_ptr->z = p[2]; + } else { + *output_ptr = *input_ptr; + } + const float & intensity = + *reinterpret_cast(&input->data[indices[i] + intensity_offset]); + output_ptr->intensity = intensity; + + output_size += output.point_step; + } } - PointXYZI out_point; - std::memcpy(&out_point, raw_p.data(), sizeof(PointXYZI)); - // FIXME(VRichardJP) tmp fix because input data does not have the same layout than PointXYZI - std::memcpy( - &out_point.intensity, &raw_p.data()[intensity_offset], sizeof(out_point.intensity)); - - std::memcpy(&output.data[output_size], &out_point, sizeof(PointXYZI)); + walk_first_idx = idx + 1; + } - output_size += sizeof(PointXYZI); + if (walk_first_idx > walk_last_idx) continue; + + if (isCluster( + input, std::make_pair(indices[walk_first_idx], indices[walk_last_idx]), + walk_last_idx - walk_first_idx + 1)) { + for (int i = walk_first_idx; i <= walk_last_idx; i++) { + auto output_ptr = reinterpret_cast(&output.data[output_size]); + auto input_ptr = reinterpret_cast(&input->data[indices[i]]); + + if (transform_info.need_transform) { + Eigen::Vector4f p(input_ptr->x, input_ptr->y, input_ptr->z, 1); + p = transform_info.eigen_transform * p; + output_ptr->x = p[0]; + output_ptr->y = p[1]; + output_ptr->z = p[2]; + } else { + *output_ptr = *input_ptr; + } + const float & intensity = + *reinterpret_cast(&input->data[indices[i] + intensity_offset]); + output_ptr->intensity = intensity; + + output_size += output.point_step; + } } } + output.data.resize(output_size); // Note that `input->header.frame_id` is data before converted when `transform_info.need_transform @@ -332,12 +196,6 @@ void RingOutlierFilterComponent::faster_filter( sensor_msgs::msg::PointField::FLOAT32, "z", 1, sensor_msgs::msg::PointField::FLOAT32, "intensity", 1, sensor_msgs::msg::PointField::FLOAT32); - if (invalid_ring_count > 0) { - RCLCPP_WARN( - get_logger(), "%d points had ring index over max_rings_num (%d) and have been ignored.", - invalid_ring_count, max_rings_num_); - } - // add processing time for debug if (debug_publisher_) { const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true); From 007d1565acc991cfb7d2fbf1c529922682ea65d9 Mon Sep 17 00:00:00 2001 From: kminoda <44218668+kminoda@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:33:47 +0900 Subject: [PATCH 005/132] chore(shape_estimation): remove unnecessary param (#6157) --- perception/shape_estimation/launch/shape_estimation.launch.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/perception/shape_estimation/launch/shape_estimation.launch.xml b/perception/shape_estimation/launch/shape_estimation.launch.xml index 65d1944417cc0..f13b5d1e5f273 100644 --- a/perception/shape_estimation/launch/shape_estimation.launch.xml +++ b/perception/shape_estimation/launch/shape_estimation.launch.xml @@ -4,9 +4,6 @@ - - - From 19f4484365bd8dc81bf54472efa96cce693e0d80 Mon Sep 17 00:00:00 2001 From: Maxime CLEMENT <78338830+maxime-clem@users.noreply.github.com> Date: Thu, 25 Jan 2024 06:56:26 +0900 Subject: [PATCH 006/132] fix(planning_evaluator): fix crashes with empty trajectories (#6129) Signed-off-by: Maxime CLEMENT --- .../planning_evaluator/src/metrics/trajectory_metrics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evaluator/planning_evaluator/src/metrics/trajectory_metrics.cpp b/evaluator/planning_evaluator/src/metrics/trajectory_metrics.cpp index d0d8d61c4c231..53265872bffa8 100644 --- a/evaluator/planning_evaluator/src/metrics/trajectory_metrics.cpp +++ b/evaluator/planning_evaluator/src/metrics/trajectory_metrics.cpp @@ -125,7 +125,7 @@ Stat calcTrajectoryLength(const Trajectory & traj) Stat calcTrajectoryDuration(const Trajectory & traj) { double duration = 0.0; - for (size_t i = 0; i < traj.points.size() - 1; ++i) { + for (size_t i = 0; i + 1 < traj.points.size(); ++i) { const double length = calcDistance2d(traj.points.at(i), traj.points.at(i + 1)); const double velocity = traj.points.at(i).longitudinal_velocity_mps; if (velocity != 0) { @@ -158,7 +158,7 @@ Stat calcTrajectoryAcceleration(const Trajectory & traj) Stat calcTrajectoryJerk(const Trajectory & traj) { Stat stat; - for (size_t i = 0; i < traj.points.size() - 1; ++i) { + for (size_t i = 0; i + 1 < traj.points.size(); ++i) { const double vel = traj.points.at(i).longitudinal_velocity_mps; if (vel != 0) { const double duration = From 1aba0ac0ade8ee292b4628bcd50949f167e66447 Mon Sep 17 00:00:00 2001 From: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Date: Thu, 25 Jan 2024 08:32:31 +0900 Subject: [PATCH 007/132] feat(tier4_automatic_goal_rviz_plugin): make it possible to register checkpoints (#6153) Signed-off-by: satoshi-ota --- .../CMakeLists.txt | 1 + .../AutowareAutomaticCheckpointTool.png | Bin 0 -> 18815 bytes .../package.xml | 3 + .../plugins/plugin_description.xml | 5 + .../src/automatic_checkpoint_append_tool.cpp | 122 +++++++++++++++++ .../src/automatic_checkpoint_append_tool.hpp | 91 +++++++++++++ .../src/automatic_goal_panel.cpp | 125 ++++++++++++------ .../src/automatic_goal_panel.hpp | 4 + .../src/automatic_goal_sender.cpp | 8 +- .../src/automatic_goal_sender.hpp | 16 ++- 10 files changed, 328 insertions(+), 47 deletions(-) create mode 100644 common/tier4_automatic_goal_rviz_plugin/icons/classes/AutowareAutomaticCheckpointTool.png create mode 100644 common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.cpp create mode 100644 common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.hpp diff --git a/common/tier4_automatic_goal_rviz_plugin/CMakeLists.txt b/common/tier4_automatic_goal_rviz_plugin/CMakeLists.txt index c6d4e30061626..cdc57743a6cb1 100644 --- a/common/tier4_automatic_goal_rviz_plugin/CMakeLists.txt +++ b/common/tier4_automatic_goal_rviz_plugin/CMakeLists.txt @@ -11,6 +11,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_definitions(-DQT_NO_KEYWORDS) ament_auto_add_library(${PROJECT_NAME} SHARED + src/automatic_checkpoint_append_tool.cpp src/automatic_goal_sender.cpp src/automatic_goal_append_tool.cpp src/automatic_goal_panel.cpp diff --git a/common/tier4_automatic_goal_rviz_plugin/icons/classes/AutowareAutomaticCheckpointTool.png b/common/tier4_automatic_goal_rviz_plugin/icons/classes/AutowareAutomaticCheckpointTool.png new file mode 100644 index 0000000000000000000000000000000000000000..6a67573717ae18b6008e00077defb27256415663 GIT binary patch literal 18815 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 QxT*u><#`b=z=h}h2b9~@i2wiq literal 0 HcmV?d00001 diff --git a/common/tier4_automatic_goal_rviz_plugin/package.xml b/common/tier4_automatic_goal_rviz_plugin/package.xml index deda078ace22e..fb5331379acb6 100644 --- a/common/tier4_automatic_goal_rviz_plugin/package.xml +++ b/common/tier4_automatic_goal_rviz_plugin/package.xml @@ -6,6 +6,8 @@ The autoware automatic goal rviz plugin package Shumpei Wakabayashi Dawid Moszyński + Kyoichi Sugahara + Satoshi Ota Apache License 2.0 Dawid Moszyński @@ -22,6 +24,7 @@ rviz_default_plugins tf2 tf2_geometry_msgs + tier4_autoware_utils visualization_msgs yaml-cpp diff --git a/common/tier4_automatic_goal_rviz_plugin/plugins/plugin_description.xml b/common/tier4_automatic_goal_rviz_plugin/plugins/plugin_description.xml index e7d5224550868..e9d77491941ed 100644 --- a/common/tier4_automatic_goal_rviz_plugin/plugins/plugin_description.xml +++ b/common/tier4_automatic_goal_rviz_plugin/plugins/plugin_description.xml @@ -9,4 +9,9 @@ base_class_type="rviz_common::Tool"> AutowareAutomaticGoalTool + + AutowareAutomaticCheckpointTool + diff --git a/common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.cpp b/common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.cpp new file mode 100644 index 0000000000000..4efa6fedbaabd --- /dev/null +++ b/common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.cpp @@ -0,0 +1,122 @@ +// 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. +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2012, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "automatic_checkpoint_append_tool.hpp" + +#ifdef ROS_DISTRO_GALACTIC +#include +#else +#include +#endif +#include + +#include + +namespace rviz_plugins +{ +AutowareAutomaticCheckpointTool::AutowareAutomaticCheckpointTool() +{ + shortcut_key_ = 'c'; + + pose_topic_property_ = new rviz_common::properties::StringProperty( + "Pose Topic", "~/automatic_goal/checkpoint", "The topic on which to publish automatic_goal.", + getPropertyContainer(), SLOT(updateTopic()), this); + std_dev_x_ = new rviz_common::properties::FloatProperty( + "X std deviation", 0.5, "X standard deviation for checkpoint pose [m]", getPropertyContainer()); + std_dev_y_ = new rviz_common::properties::FloatProperty( + "Y std deviation", 0.5, "Y standard deviation for checkpoint pose [m]", getPropertyContainer()); + std_dev_theta_ = new rviz_common::properties::FloatProperty( + "Theta std deviation", M_PI / 12.0, "Theta standard deviation for checkpoint pose [rad]", + getPropertyContainer()); + position_z_ = new rviz_common::properties::FloatProperty( + "Z position", 0.0, "Z position for checkpoint pose [m]", getPropertyContainer()); + std_dev_x_->setMin(0); + std_dev_y_->setMin(0); + std_dev_theta_->setMin(0); + position_z_->setMin(0); +} + +void AutowareAutomaticCheckpointTool::onInitialize() +{ + PoseTool::onInitialize(); + setName("2D AppendCheckpoint"); + updateTopic(); +} + +void AutowareAutomaticCheckpointTool::updateTopic() +{ + rclcpp::Node::SharedPtr raw_node = context_->getRosNodeAbstraction().lock()->get_raw_node(); + pose_pub_ = raw_node->create_publisher( + pose_topic_property_->getStdString(), 1); + clock_ = raw_node->get_clock(); +} + +void AutowareAutomaticCheckpointTool::onPoseSet(double x, double y, double theta) +{ + // pose + std::string fixed_frame = context_->getFixedFrame().toStdString(); + geometry_msgs::msg::PoseStamped pose; + pose.header.frame_id = fixed_frame; + pose.header.stamp = clock_->now(); + pose.pose.position.x = x; + pose.pose.position.y = y; + pose.pose.position.z = position_z_->getFloat(); + + tf2::Quaternion quat; + quat.setRPY(0.0, 0.0, theta); + pose.pose.orientation = tf2::toMsg(quat); + RCLCPP_INFO( + rclcpp::get_logger("AutowareAutomaticCheckpointTool"), + "Setting pose: %.3f %.3f %.3f %.3f [frame=%s]", x, y, position_z_->getFloat(), theta, + fixed_frame.c_str()); + pose_pub_->publish(pose); +} + +} // end namespace rviz_plugins + +#include +PLUGINLIB_EXPORT_CLASS(rviz_plugins::AutowareAutomaticCheckpointTool, rviz_common::Tool) diff --git a/common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.hpp b/common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.hpp new file mode 100644 index 0000000000000..4ea3fa4bd009a --- /dev/null +++ b/common/tier4_automatic_goal_rviz_plugin/src/automatic_checkpoint_append_tool.hpp @@ -0,0 +1,91 @@ +// 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. +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2012, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AUTOMATIC_CHECKPOINT_APPEND_TOOL_HPP_ +#define AUTOMATIC_CHECKPOINT_APPEND_TOOL_HPP_ + +#ifndef Q_MOC_RUN // See: https://bugreports.qt-project.org/browse/QTBUG-22829 +#include +#include +#include +#include +#include +#include +#endif + +#include + +namespace rviz_plugins +{ +class AutowareAutomaticCheckpointTool : public rviz_default_plugins::tools::PoseTool +{ + Q_OBJECT + +public: + AutowareAutomaticCheckpointTool(); + void onInitialize() override; + +protected: + void onPoseSet(double x, double y, double theta) override; + +private Q_SLOTS: + void updateTopic(); + +private: // NOLINT for Qt + rclcpp::Clock::SharedPtr clock_{nullptr}; + rclcpp::Publisher::SharedPtr pose_pub_{nullptr}; + + rviz_common::properties::StringProperty * pose_topic_property_{nullptr}; + rviz_common::properties::FloatProperty * std_dev_x_{nullptr}; + rviz_common::properties::FloatProperty * std_dev_y_{nullptr}; + rviz_common::properties::FloatProperty * std_dev_theta_{nullptr}; + rviz_common::properties::FloatProperty * position_z_{nullptr}; +}; + +} // namespace rviz_plugins + +#endif // AUTOMATIC_CHECKPOINT_APPEND_TOOL_HPP_ diff --git a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.cpp b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.cpp index bee390bfe29ed..6b8d7765a989a 100644 --- a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.cpp +++ b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.cpp @@ -16,6 +16,8 @@ #include "automatic_goal_panel.hpp" +#include + namespace rviz_plugins { AutowareAutomaticGoalPanel::AutowareAutomaticGoalPanel(QWidget * parent) @@ -139,6 +141,9 @@ void AutowareAutomaticGoalPanel::onInitialize() sub_append_goal_ = raw_node_->create_subscription( "~/automatic_goal/goal", 5, std::bind(&AutowareAutomaticGoalPanel::onAppendGoal, this, std::placeholders::_1)); + sub_append_checkpoint_ = raw_node_->create_subscription( + "~/automatic_goal/checkpoint", 5, + std::bind(&AutowareAutomaticGoalPanel::onAppendCheckpoint, this, std::placeholders::_1)); initCommunication(raw_node_.get()); } @@ -244,12 +249,28 @@ void AutowareAutomaticGoalPanel::onClickSaveListToFile() void AutowareAutomaticGoalPanel::onAppendGoal(const PoseStamped::ConstSharedPtr pose) { if (state_ == State::EDITING) { - goals_list_.push_back(pose); + goals_list_.emplace_back(pose); updateGoalsList(); updateGUI(); } } +void AutowareAutomaticGoalPanel::onAppendCheckpoint(const PoseStamped::ConstSharedPtr pose) +{ + if (goals_list_widget_ptr_->selectedItems().count() != 1) { + showMessageBox("Select a goal in GoalsList before set checkpoint"); + return; + } + + current_goal_ = goals_list_widget_ptr_->currentRow(); + if (current_goal_ >= goals_list_.size()) { + return; + } + + goals_list_.at(current_goal_).checkpoint_pose_ptrs.push_back(pose); + publishMarkers(); +} + // Override void AutowareAutomaticGoalPanel::onCallResult() { @@ -418,47 +439,71 @@ void AutowareAutomaticGoalPanel::updateGoalIcon(const unsigned goal_index, const void AutowareAutomaticGoalPanel::publishMarkers() { + using tier4_autoware_utils::createDefaultMarker; + using tier4_autoware_utils::createMarkerColor; + using tier4_autoware_utils::createMarkerScale; + MarkerArray text_array; MarkerArray arrow_array; // Clear existing - visualization_msgs::msg::Marker marker; - marker.header.stamp = rclcpp::Time(); - marker.ns = "names"; - marker.id = 0; - marker.action = visualization_msgs::msg::Marker::DELETEALL; - text_array.markers.push_back(marker); - marker.ns = "poses"; - arrow_array.markers.push_back(marker); - pub_marker_->publish(text_array); - pub_marker_->publish(arrow_array); + { + auto marker = createDefaultMarker( + "map", rclcpp::Clock{RCL_ROS_TIME}.now(), "names", 0L, Marker::CUBE, + createMarkerScale(1.0, 1.0, 1.0), createMarkerColor(1.0, 1.0, 1.0, 0.999)); + marker.action = visualization_msgs::msg::Marker::DELETEALL; + text_array.markers.push_back(marker); + pub_marker_->publish(text_array); + } + + { + auto marker = createDefaultMarker( + "map", rclcpp::Clock{RCL_ROS_TIME}.now(), "poses", 0L, Marker::CUBE, + createMarkerScale(1.0, 1.0, 1.0), createMarkerColor(1.0, 1.0, 1.0, 0.999)); + arrow_array.markers.push_back(marker); + pub_marker_->publish(arrow_array); + } + text_array.markers.clear(); arrow_array.markers.clear(); - // Publish current - for (unsigned i = 0; i < goals_list_.size(); i++) { - visualization_msgs::msg::Marker marker; - marker.header.frame_id = "map"; - marker.header.stamp = rclcpp::Time(); - marker.ns = "names"; - marker.id = static_cast(i); - marker.type = visualization_msgs::msg::Marker::TEXT_VIEW_FACING; + + const auto push_arrow_marker = [&](const auto & pose, const auto & color, const size_t id) { + auto marker = createDefaultMarker( + "map", rclcpp::Clock{RCL_ROS_TIME}.now(), "poses", id, Marker::ARROW, + createMarkerScale(1.6, 0.5, 0.5), color); marker.action = visualization_msgs::msg::Marker::ADD; - marker.pose = goals_list_[i]->pose; + marker.pose = pose; marker.lifetime = rclcpp::Duration(0, 0); - marker.scale.x = 1.6; - marker.scale.y = 1.6; - marker.scale.z = 1.6; - marker.color.r = 1.0; - marker.color.g = 1.0; - marker.color.b = 1.0; - marker.color.a = 1.0; marker.frame_locked = false; - marker.text = "G" + std::to_string(i); - text_array.markers.push_back(marker); - marker.ns = "poses"; - marker.scale.y = 0.2; - marker.scale.z = 0.2; - marker.type = visualization_msgs::msg::Marker::ARROW; arrow_array.markers.push_back(marker); + }; + + const auto push_text_marker = [&](const auto & pose, const auto & text, const size_t id) { + auto marker = createDefaultMarker( + "map", rclcpp::Clock{RCL_ROS_TIME}.now(), "names", id, Marker::TEXT_VIEW_FACING, + createMarkerScale(1.6, 1.6, 1.6), createMarkerColor(1.0, 1.0, 1.0, 0.999)); + marker.action = visualization_msgs::msg::Marker::ADD; + marker.pose = pose; + marker.lifetime = rclcpp::Duration(0, 0); + marker.frame_locked = false; + marker.text = text; + text_array.markers.push_back(marker); + }; + + // Publish current + size_t id = 0; + for (size_t i = 0; i < goals_list_.size(); ++i) { + { + const auto pose = goals_list_.at(i).goal_pose_ptr->pose; + push_arrow_marker(pose, createMarkerColor(0.0, 1.0, 0.0, 0.999), id++); + push_text_marker(pose, "Goal:" + std::to_string(i), id++); + } + + for (size_t j = 0; j < goals_list_.at(i).checkpoint_pose_ptrs.size(); ++j) { + const auto pose = goals_list_.at(i).checkpoint_pose_ptrs.at(j)->pose; + push_arrow_marker(pose, createMarkerColor(1.0, 1.0, 0.0, 0.999), id++); + push_text_marker( + pose, "Checkpoint:" + std::to_string(i) + "[Goal:" + std::to_string(j) + "]", id++); + } } pub_marker_->publish(text_array); pub_marker_->publish(arrow_array); @@ -469,13 +514,13 @@ void AutowareAutomaticGoalPanel::saveGoalsList(const std::string & file_path) { YAML::Node node; for (unsigned i = 0; i < goals_list_.size(); ++i) { - node[i]["position_x"] = goals_list_[i]->pose.position.x; - node[i]["position_y"] = goals_list_[i]->pose.position.y; - node[i]["position_z"] = goals_list_[i]->pose.position.z; - node[i]["orientation_x"] = goals_list_[i]->pose.orientation.x; - node[i]["orientation_y"] = goals_list_[i]->pose.orientation.y; - node[i]["orientation_z"] = goals_list_[i]->pose.orientation.z; - node[i]["orientation_w"] = goals_list_[i]->pose.orientation.w; + node[i]["position_x"] = goals_list_[i].goal_pose_ptr->pose.position.x; + node[i]["position_y"] = goals_list_[i].goal_pose_ptr->pose.position.y; + node[i]["position_z"] = goals_list_[i].goal_pose_ptr->pose.position.z; + node[i]["orientation_x"] = goals_list_[i].goal_pose_ptr->pose.orientation.x; + node[i]["orientation_y"] = goals_list_[i].goal_pose_ptr->pose.orientation.y; + node[i]["orientation_z"] = goals_list_[i].goal_pose_ptr->pose.orientation.z; + node[i]["orientation_w"] = goals_list_[i].goal_pose_ptr->pose.orientation.w; } std::ofstream file_out(file_path); file_out << node; diff --git a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.hpp b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.hpp index 0ec9ca530f074..72a5bd4fb80fe 100644 --- a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.hpp +++ b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_panel.hpp @@ -61,7 +61,9 @@ class AutowareAutomaticGoalPanel : public rviz_common::Panel, public automatic_goal::AutowareAutomaticGoalSender { using State = automatic_goal::AutomaticGoalState; + using Pose = geometry_msgs::msg::Pose; using PoseStamped = geometry_msgs::msg::PoseStamped; + using Marker = visualization_msgs::msg::Marker; using MarkerArray = visualization_msgs::msg::MarkerArray; using OperationModeState = autoware_adapi_v1_msgs::msg::OperationModeState; using ChangeOperationMode = autoware_adapi_v1_msgs::srv::ChangeOperationMode; @@ -96,6 +98,7 @@ public Q_SLOTS: // NOLINT for Qt // Inputs void onAppendGoal(const PoseStamped::ConstSharedPtr pose); + void onAppendCheckpoint(const PoseStamped::ConstSharedPtr pose); // Visual updates void updateGUI(); @@ -116,6 +119,7 @@ public Q_SLOTS: // NOLINT for Qt // Pub/Sub rclcpp::Publisher::SharedPtr pub_marker_{nullptr}; rclcpp::Subscription::SharedPtr sub_append_goal_{nullptr}; + rclcpp::Subscription::SharedPtr sub_append_checkpoint_{nullptr}; // Containers rclcpp::Node::SharedPtr raw_node_{nullptr}; diff --git a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.cpp b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.cpp index cc8d46e2f60c6..3ca368a3bd1a4 100644 --- a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.cpp +++ b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.cpp @@ -108,9 +108,9 @@ void AutowareAutomaticGoalSender::updateGoalsList() std::stringstream ss; ss << std::fixed << std::setprecision(2); tf2::Quaternion tf2_quat; - tf2::convert(goal->pose.orientation, tf2_quat); - ss << "G" << i << " (" << goal->pose.position.x << ", "; - ss << goal->pose.position.y << ", " << tf2::getYaw(tf2_quat) << ")"; + tf2::convert(goal.goal_pose_ptr->pose.orientation, tf2_quat); + ss << "G" << i << " (" << goal.goal_pose_ptr->pose.position.x << ", "; + ss << goal.goal_pose_ptr->pose.position.y << ", " << tf2::getYaw(tf2_quat) << ")"; goals_achieved_.insert({i++, std::make_pair(ss.str(), 0)}); } onGoalListUpdated(); @@ -178,7 +178,7 @@ void AutowareAutomaticGoalSender::loadGoalsList(const std::string & file_path) pose->pose.orientation.y = goal["orientation_y"].as(); pose->pose.orientation.z = goal["orientation_z"].as(); pose->pose.orientation.w = goal["orientation_w"].as(); - goals_list_.push_back(pose); + goals_list_.emplace_back(pose); } resetAchievedGoals(); updateGoalsList(); diff --git a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.hpp b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.hpp index aacdada352811..88b7b5e7dac20 100644 --- a/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.hpp +++ b/common/tier4_automatic_goal_rviz_plugin/src/automatic_goal_sender.hpp @@ -80,8 +80,11 @@ class AutowareAutomaticGoalSender : public rclcpp::Node } auto req = std::make_shared(); - req->header = goals_list_.at(goal_index)->header; - req->goal = goals_list_.at(goal_index)->pose; + req->header = goals_list_.at(goal_index).goal_pose_ptr->header; + req->goal = goals_list_.at(goal_index).goal_pose_ptr->pose; + for (const auto & checkpoint : goals_list_.at(goal_index).checkpoint_pose_ptrs) { + req->waypoints.push_back(checkpoint->pose); + } client->async_send_request( req, [this](typename rclcpp::Client::SharedFuture result) { if (result.get()->status.code != 0) state_ = State::ERROR; @@ -120,6 +123,13 @@ class AutowareAutomaticGoalSender : public rclcpp::Node } } + struct Route + { + explicit Route(const PoseStamped::ConstSharedPtr & goal) : goal_pose_ptr{goal} {} + PoseStamped::ConstSharedPtr goal_pose_ptr{}; + std::vector checkpoint_pose_ptrs{}; + }; + // Update void updateGoalsList(); virtual void updateAutoExecutionTimerTick(); @@ -155,7 +165,7 @@ class AutowareAutomaticGoalSender : public rclcpp::Node // Containers unsigned current_goal_{0}; State state_{State::INITIALIZING}; - std::vector goals_list_{}; + std::vector goals_list_{}; std::map> goals_achieved_{}; std::string goals_achieved_file_path_{}; From 2719ad4d830f93787979905714beb18b7d2ea720 Mon Sep 17 00:00:00 2001 From: Taekjin LEE Date: Thu, 25 Jan 2024 08:52:12 +0900 Subject: [PATCH 008/132] refactor(tier4_perception_launch): refactor object_recognition/detection launcher (#6152) * refactor: align mode parameters Signed-off-by: Taekjin LEE * refactor: cluster detector and merger Signed-off-by: Taekjin LEE * refactor: separate object merger launches Signed-off-by: Taekjin LEE * refactor: radar detector module Signed-off-by: Taekjin LEE * refactor: lidar detector modules Signed-off-by: Taekjin LEE * chore: fix mis spell, align typo, clean-up Signed-off-by: Taekjin LEE --------- Signed-off-by: Taekjin LEE --- ...ar_radar_fusion_based_detection.launch.xml | 437 ------------------ .../detection/detection.launch.xml | 145 +++++- .../camera_lidar_detector.launch.xml} | 236 ++-------- .../detector/lidar_dnn_detector.launch.xml | 56 +++ .../detector/lidar_rule_detector.launch.xml | 55 +++ .../radar_detector.launch.xml} | 0 .../lidar_radar_based_detection.launch.xml | 51 -- .../merger/camera_lidar_merger.launch.xml | 124 +++++ .../camera_lidar_radar_merger.launch.xml | 154 ++++++ .../lidar_merger.launch.xml} | 114 +---- 10 files changed, 563 insertions(+), 809 deletions(-) delete mode 100644 launch/tier4_perception_launch/launch/object_recognition/detection/camera_lidar_radar_fusion_based_detection.launch.xml rename launch/tier4_perception_launch/launch/object_recognition/detection/{camera_lidar_fusion_based_detection.launch.xml => detector/camera_lidar_detector.launch.xml} (57%) create mode 100644 launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_dnn_detector.launch.xml create mode 100644 launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_rule_detector.launch.xml rename launch/tier4_perception_launch/launch/object_recognition/detection/{radar_based_detection.launch.xml => detector/radar_detector.launch.xml} (100%) delete mode 100644 launch/tier4_perception_launch/launch/object_recognition/detection/lidar_radar_based_detection.launch.xml create mode 100644 launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_merger.launch.xml create mode 100644 launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_radar_merger.launch.xml rename launch/tier4_perception_launch/launch/object_recognition/detection/{lidar_based_detection.launch.xml => merger/lidar_merger.launch.xml} (51%) diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/camera_lidar_radar_fusion_based_detection.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/camera_lidar_radar_fusion_based_detection.launch.xml deleted file mode 100644 index ba86bc1e334ff..0000000000000 --- a/launch/tier4_perception_launch/launch/object_recognition/detection/camera_lidar_radar_fusion_based_detection.launch.xml +++ /dev/null @@ -1,437 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml index 885fa80ed7004..ab9ed65999048 100644 --- a/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml @@ -3,7 +3,7 @@ - + @@ -34,9 +34,10 @@ - + - + + @@ -57,23 +58,61 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + @@ -94,47 +133,107 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + - + - - - + + + + + + + + + + + + + - + - + + + + + - + - - + + + + + + - + + diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/camera_lidar_fusion_based_detection.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/camera_lidar_detector.launch.xml similarity index 57% rename from launch/tier4_perception_launch/launch/object_recognition/detection/camera_lidar_fusion_based_detection.launch.xml rename to launch/tier4_perception_launch/launch/object_recognition/detection/detector/camera_lidar_detector.launch.xml index 4cb648852a03c..1c9201a9af8b3 100644 --- a/launch/tier4_perception_launch/launch/object_recognition/detection/camera_lidar_fusion_based_detection.launch.xml +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/camera_lidar_detector.launch.xml @@ -1,17 +1,13 @@ - - - - + - - - - + + + @@ -54,6 +50,44 @@ --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -192,190 +226,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_dnn_detector.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_dnn_detector.launch.xml new file mode 100644 index 0000000000000..1a97659b357d8 --- /dev/null +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_dnn_detector.launch.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_rule_detector.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_rule_detector.launch.xml new file mode 100644 index 0000000000000..ce34640bd3179 --- /dev/null +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/lidar_rule_detector.launch.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/radar_based_detection.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/radar_detector.launch.xml similarity index 100% rename from launch/tier4_perception_launch/launch/object_recognition/detection/radar_based_detection.launch.xml rename to launch/tier4_perception_launch/launch/object_recognition/detection/detector/radar_detector.launch.xml diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/lidar_radar_based_detection.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/lidar_radar_based_detection.launch.xml deleted file mode 100644 index adedc2312677f..0000000000000 --- a/launch/tier4_perception_launch/launch/object_recognition/detection/lidar_radar_based_detection.launch.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_merger.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_merger.launch.xml new file mode 100644 index 0000000000000..2f62e83ae0ef5 --- /dev/null +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_merger.launch.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_radar_merger.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_radar_merger.launch.xml new file mode 100644 index 0000000000000..b4d19c9052a63 --- /dev/null +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/merger/camera_lidar_radar_merger.launch.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/lidar_based_detection.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/merger/lidar_merger.launch.xml similarity index 51% rename from launch/tier4_perception_launch/launch/object_recognition/detection/lidar_based_detection.launch.xml rename to launch/tier4_perception_launch/launch/object_recognition/detection/merger/lidar_merger.launch.xml index 04c4264b70e5f..6ccff44933966 100644 --- a/launch/tier4_perception_launch/launch/object_recognition/detection/lidar_based_detection.launch.xml +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/merger/lidar_merger.launch.xml @@ -1,113 +1,19 @@ - - + - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - + + + @@ -133,9 +39,9 @@ - - - + + + From 20ff907be39c926c094721eecb682be9a77145fe Mon Sep 17 00:00:00 2001 From: SakodaShintaro Date: Thu, 25 Jan 2024 13:11:50 +0900 Subject: [PATCH 009/132] chore(ar_tag_based_localizer): add json schema (#6164) * Added json schema to AR tag-based localizer Signed-off-by: Shintaro SAKODA * style(pre-commit): autofix --------- Signed-off-by: Shintaro SAKODA Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../ar_tag_based_localizer/README.md | 6 +- .../schema/ar_tag_based_localizer.schema.json | 87 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 localization/landmark_based_localizer/ar_tag_based_localizer/schema/ar_tag_based_localizer.schema.json diff --git a/localization/landmark_based_localizer/ar_tag_based_localizer/README.md b/localization/landmark_based_localizer/ar_tag_based_localizer/README.md index f0c54d6393f7e..1a776bd810fff 100644 --- a/localization/landmark_based_localizer/ar_tag_based_localizer/README.md +++ b/localization/landmark_based_localizer/ar_tag_based_localizer/README.md @@ -2,7 +2,7 @@ **ArTagBasedLocalizer** is a vision-based localization node. - +ar_tag_image This node uses [the ArUco library](https://index.ros.org/p/aruco/) to detect AR-Tags from camera images and calculates and publishes the pose of the ego vehicle based on these detections. The positions and orientations of the AR-Tags are assumed to be written in the Lanelet2 format. @@ -30,6 +30,10 @@ The positions and orientations of the AR-Tags are assumed to be written in the L | `/tf` | `geometry_msgs::msg::TransformStamped` | [debug topic] TF from camera to detected tag | | `/diagnostics` | `diagnostic_msgs::msg::DiagnosticArray` | Diagnostics outputs | +## Parameters + +{{ json_to_markdown("localization/landmark_based_localizer/ar_tag_based_localizer/schema/ar_tag_based_localizer.schema.json") }} + ## How to launch When launching Autoware, set `artag` for `pose_source`. diff --git a/localization/landmark_based_localizer/ar_tag_based_localizer/schema/ar_tag_based_localizer.schema.json b/localization/landmark_based_localizer/ar_tag_based_localizer/schema/ar_tag_based_localizer.schema.json new file mode 100644 index 0000000000000..bde5221aa1bbc --- /dev/null +++ b/localization/landmark_based_localizer/ar_tag_based_localizer/schema/ar_tag_based_localizer.schema.json @@ -0,0 +1,87 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for ar_tag_based_localizer", + "type": "object", + "definitions": { + "ar_tag_based_localizer": { + "type": "object", + "properties": { + "marker_size": { + "type": "number", + "description": "marker_size", + "default": 0.6 + }, + "target_tag_ids": { + "type": "array", + "description": "target_tag_ids", + "default": "['0','1','2','3','4','5','6']" + }, + "base_covariance": { + "type": "array", + "description": "base_covariance", + "default": [ + 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.02 + ] + }, + "distance_threshold": { + "type": "number", + "description": "distance_threshold(m)", + "default": "13.0" + }, + "consider_orientation": { + "type": "boolean", + "description": "consider_orientation", + "default": "false" + }, + "detection_mode": { + "type": "string", + "description": "detection_mode select from [DM_NORMAL, DM_FAST, DM_VIDEO_FAST]", + "default": "DM_NORMAL" + }, + "min_marker_size": { + "type": "number", + "description": "min_marker_size", + "default": 0.02 + }, + "ekf_time_tolerance": { + "type": "number", + "description": "ekf_time_tolerance(sec)", + "default": 5.0 + }, + "ekf_position_tolerance": { + "type": "number", + "description": "ekf_position_tolerance(m)", + "default": 10.0 + } + }, + "required": [ + "marker_size", + "target_tag_ids", + "base_covariance", + "distance_threshold", + "consider_orientation", + "detection_mode", + "min_marker_size", + "ekf_time_tolerance", + "ekf_position_tolerance" + ], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/ar_tag_based_localizer" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} From 1a9dbf4532d8315bd443ad2732cb4fbd34c23673 Mon Sep 17 00:00:00 2001 From: Yamato Ando Date: Thu, 25 Jan 2024 14:39:55 +0900 Subject: [PATCH 010/132] fix(ndt_scan_matcher): fix type of critical_upper_bound_exe_time_ms (#6161) * fix type of critical_upper_bound_exe_time_ms Signed-off-by: Yamato Ando * fix order Signed-off-by: Yamato Ando --------- Signed-off-by: Yamato Ando --- .../ndt_scan_matcher/config/ndt_scan_matcher.param.yaml | 6 +++--- .../include/ndt_scan_matcher/ndt_scan_matcher_core.hpp | 2 +- localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml b/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml index 9bc62d3f919c6..a5a4941bfec62 100644 --- a/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml +++ b/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml @@ -54,6 +54,9 @@ # Tolerance of distance difference between two initial poses used for linear interpolation. [m] initial_pose_distance_tolerance_m: 10.0 + # The execution time which means probably NDT cannot matches scans properly. [ms] + critical_upper_bound_exe_time_ms: 100.0 + # Number of threads used for parallel computing num_threads: 4 @@ -98,6 +101,3 @@ # If lidar_point.z - base_link.z <= this threshold , the point will be removed z_margin_for_ground_removal: 0.8 - - # The execution time which means probably NDT cannot matches scans properly. [ms] - critical_upper_bound_exe_time_ms: 100 diff --git a/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp b/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp index 71895c59ec37d..e2503c20aef6e 100644 --- a/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp +++ b/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp @@ -225,7 +225,7 @@ class NDTScanMatcher : public rclcpp::Node double z_margin_for_ground_removal_; // The execution time which means probably NDT cannot matches scans properly - int64_t critical_upper_bound_exe_time_ms_; + double critical_upper_bound_exe_time_ms_; }; #endif // NDT_SCAN_MATCHER__NDT_SCAN_MATCHER_CORE_HPP_ diff --git a/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp b/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp index 942df03410165..0382d805b7276 100644 --- a/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp +++ b/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp @@ -118,7 +118,7 @@ NDTScanMatcher::NDTScanMatcher() lidar_topic_timeout_sec_ = this->declare_parameter("lidar_topic_timeout_sec"); critical_upper_bound_exe_time_ms_ = - this->declare_parameter("critical_upper_bound_exe_time_ms"); + this->declare_parameter("critical_upper_bound_exe_time_ms"); initial_pose_timeout_sec_ = this->declare_parameter("initial_pose_timeout_sec"); @@ -316,8 +316,7 @@ void NDTScanMatcher::publish_diagnostic() } if ( state_ptr_->count("execution_time") && - std::stod((*state_ptr_)["execution_time"]) >= - static_cast(critical_upper_bound_exe_time_ms_)) { + std::stod((*state_ptr_)["execution_time"]) >= critical_upper_bound_exe_time_ms_) { diag_status_msg.level = diagnostic_msgs::msg::DiagnosticStatus::WARN; diag_status_msg.message += "NDT exe time is too long. (took " + (*state_ptr_)["execution_time"] + " [ms])"; From 6bf7532a0299e9d0c0be18529d9fe42f1660c6bd Mon Sep 17 00:00:00 2001 From: Yamato Ando Date: Thu, 25 Jan 2024 14:40:24 +0900 Subject: [PATCH 011/132] refactor(localization_error_monitor): rework parameters (#6156) * refactor(localization_error_monitor): rework parameters Signed-off-by: Yamato Ando * style(pre-commit): autofix --------- Signed-off-by: Yamato Ando Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../localization_error_monitor/README.md | 8 +-- .../localization_error_monitor.schema.json | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 localization/localization_error_monitor/schema/localization_error_monitor.schema.json diff --git a/localization/localization_error_monitor/README.md b/localization/localization_error_monitor/README.md index 2ddf41e4eac70..7912ad843ef19 100644 --- a/localization/localization_error_monitor/README.md +++ b/localization/localization_error_monitor/README.md @@ -29,10 +29,4 @@ The package monitors the following two values: ## Parameters -| Name | Type | Description | -| -------------------------------------- | ------ | -------------------------------------------------------------------------------------------- | -| `scale` | double | scale factor for monitored values (default: 3.0) | -| `error_ellipse_size` | double | error threshold for long radius of confidence ellipse [m] (default: 1.0) | -| `warn_ellipse_size` | double | warning threshold for long radius of confidence ellipse [m] (default: 0.8) | -| `error_ellipse_size_lateral_direction` | double | error threshold for size of confidence ellipse along lateral direction [m] (default: 0.3) | -| `warn_ellipse_size_lateral_direction` | double | warning threshold for size of confidence ellipse along lateral direction [m] (default: 0.25) | +{{ json_to_markdown("localization/localization_error_monitor/schema/localization_error_monitor.schema.json") }} diff --git a/localization/localization_error_monitor/schema/localization_error_monitor.schema.json b/localization/localization_error_monitor/schema/localization_error_monitor.schema.json new file mode 100644 index 0000000000000..0cdd5fb946756 --- /dev/null +++ b/localization/localization_error_monitor/schema/localization_error_monitor.schema.json @@ -0,0 +1,56 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for Localization Error Monitor node", + "type": "object", + "definitions": { + "localization_error_monitor": { + "type": "object", + "properties": { + "scale": { + "type": "number", + "default": 3.0, + "description": "scale factor for monitored values" + }, + "error_ellipse_size": { + "type": "number", + "default": 1.5, + "description": "error threshold for long radius of confidence ellipse [m]" + }, + "warn_ellipse_size": { + "type": "number", + "default": 1.2, + "description": "warning threshold for long radius of confidence ellipse [m]" + }, + "error_ellipse_size_lateral_direction": { + "type": "number", + "default": 0.3, + "description": "error threshold for size of confidence ellipse along lateral direction [m]" + }, + "warn_ellipse_size_lateral_direction": { + "type": "number", + "default": 0.25, + "description": "warning threshold for size of confidence ellipse along lateral direction [m]" + } + }, + "required": [ + "scale", + "error_ellipse_size", + "warn_ellipse_size", + "error_ellipse_size_lateral_direction", + "warn_ellipse_size_lateral_direction" + ] + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/localization_error_monitor" + } + }, + "required": ["ros__parameters"] + } + }, + "required": ["/**"] +} From 98f2a71eaa0c7f06c766ae8b91621fe1e8173c41 Mon Sep 17 00:00:00 2001 From: Satoshi Tanaka <16330533+scepter914@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:11:47 +0900 Subject: [PATCH 012/132] chore(simple_object_merger): update README (#6146) * chore(simple_object_merger): update README Signed-off-by: scepter914 * style(pre-commit): autofix * update README Signed-off-by: scepter914 * style(pre-commit): autofix * update README Signed-off-by: scepter914 --------- Signed-off-by: scepter914 Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- perception/simple_object_merger/README.md | 86 ++++++++++++++--------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/perception/simple_object_merger/README.md b/perception/simple_object_merger/README.md index 4609638cc008c..9bcd03e8abfa1 100644 --- a/perception/simple_object_merger/README.md +++ b/perception/simple_object_merger/README.md @@ -1,60 +1,78 @@ # simple_object_merger -This package can merge multiple topics of [autoware_auto_perception_msgs/msg/DetectedObject](https://gitlab.com/autowarefoundation/autoware.auto/autoware_auto_msgs/-/blob/master/autoware_auto_perception_msgs/msg/DetectedObject.idl) without data association algorithm. +This package can merge multiple topics of [autoware_auto_perception_msgs/msg/DetectedObject](https://gitlab.com/autowarefoundation/autoware.auto/autoware_auto_msgs/-/blob/master/autoware_auto_perception_msgs/msg/DetectedObject.idl) without low calculation cost. ## Algorithm ### Background -This package can merge multiple DetectedObjects without matching processing. -[Object_merger](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/object_merger) solve data association algorithm like Hungarian algorithm for matching problem, but it needs computational cost. -In addition, for now, [object_merger](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/object_merger) can handle only 2 DetectedObjects topics and cannot handle more than 2 topics in one node. -To merge 6 DetectedObjects topics, 6 [object_merger](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/object_merger) nodes need to stand. +[Object_merger](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/object_merger) is mainly used for merge process with DetectedObjects. There are 2 characteristics in `Object_merger`. First, `object_merger` solve data association algorithm like Hungarian algorithm for matching problem, but it needs computational cost. Second, `object_merger` can handle only 2 DetectedObjects topics and cannot handle more than 2 topics in one node. To merge 6 DetectedObjects topics, 6 `object_merger` nodes need to stand for now. -So this package aim to merge DetectedObjects simply. -This package do not use data association algorithm to reduce the computational cost, and it can handle more than 2 topics in one node to prevent launching a large number of nodes. +So `simple_object_merger` aim to merge multiple DetectedObjects with low calculation cost. +The package do not use data association algorithm to reduce the computational cost, and it can handle more than 2 topics in one node to prevent launching a large number of nodes. + +### Use case + +Use case is as below. + +- Multiple radar detection + +`Simple_object_merger` can be used for multiple radar detection. By combining them into one topic from multiple radar topics with `simple_object_merger`, the pipeline for faraway detection with radar is simpler. ### Limitation - Sensor data drops and delay -Merged objects will not be published until all topic data is received when initializing. -In addition, to care sensor data drops and delayed, this package has a parameter to judge timeout. -When the latest time of the data of a topic is older than the timeout parameter, it is not merged for output objects. -For now specification of this package, if all topic data is received at first and after that the data drops, and the merged objects are published without objects which is judged as timeout. -The timeout parameter should be determined by sensor cycle time. +Merged objects will not be published until all topic data is received when initializing. In addition, to care sensor data drops and delayed, this package has a parameter to judge timeout. When the latest time of the data of a topic is older than the timeout parameter, it is not merged for output objects. For now specification of this package, if all topic data is received at first and after that the data drops, and the merged objects are published without objects which is judged as timeout.The timeout parameter should be determined by sensor cycle time. - Post-processing -Because this package does not have matching processing, so it can be used only when post-processing is used. -For now, [clustering processing](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/radar_object_clustering) can be used as post-processing. +Because this package does not have matching processing, there are overlapping objects depending on the input objects. So output objects can be used only when post-processing is used. For now, [clustering processing](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/radar_object_clustering) can be used as post-processing. -### Use case +## Interface -Use case is as below. +### Input -- Multiple radar detection +Input topics is defined by the parameter of `input_topics` (List[string]). The type of input topics is `std::vector`. + +### Output + +- `~/output/objects` (`autoware_auto_perception_msgs/msg/DetectedObjects.msg`) + - Merged objects combined from input topics. + +### Parameters + +- `update_rate_hz` (double) [hz] + - Default parameter: 20.0 + +This parameter is update rate for the `onTimer` function. +This parameter should be same as the frame rate of input topics. -This package can be used for multiple radar detection. -Since [clustering processing](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/radar_object_clustering) will be included later process in radar faraway detection, this package can be used. +- `new_frame_id` (string) + - Default parameter: "base_link" -## Input +This parameter is the header frame_id of the output topic. +If output topics use for perception module, it should be set for "base_link" -| Name | Type | Description | -| ---- | ------------------------------------------------------------------ | ------------------------------------------------------ | -| | std::vector | 3D detected objects. Topic names are set by parameters | +- `timeout_threshold` (double) [s] + - Default parameter: 0.1 -## Output +This parameter is the threshold for timeout judgement. +If the time difference between the first topic of `input_topics` and an input topic is exceeded to this parameter, then the objects of topic is not merged to output objects. -| Name | Type | Description | -| ------------------ | ----------------------------------------------------- | -------------- | -| `~/output/objects` | autoware_auto_perception_msgs/msg/DetectedObjects.msg | Merged objects | +```cpp + for (size_t i = 0; i < input_topic_size; i++) { + double time_diff = rclcpp::Time(objects_data_.at(i)->header.stamp).seconds() - + rclcpp::Time(objects_data_.at(0)->header.stamp).seconds(); + if (std::abs(time_diff) < node_param_.timeout_threshold) { + // merge objects + } + } +``` -## Parameters +- `input_topics` (List[string]) + - Default parameter: "[]" -| Name | Type | Description | Default value | -| :------------------ | :----------- | :----------------------------------- | :------------ | -| `update_rate_hz` | double | Update rate. [hz] | 20.0 | -| `new_frame_id` | string | The header frame_id of output topic. | "base_link" | -| `timeout_threshold` | double | Threshold for timeout judgement [s]. | 1.0 | -| `input_topics` | List[string] | Input topics name. | "[]" | +This parameter is the name of input topics. +For example, when this packages use for radar objects, `"[/sensing/radar/front_center/detected_objects, /sensing/radar/front_left/detected_objects, /sensing/radar/rear_left/detected_objects, /sensing/radar/rear_center/detected_objects, /sensing/radar/rear_right/detected_objects, /sensing/radar/front_right/detected_objects]"` can be set. +For now, the time difference is calculated by the header time between the first topic of `input_topics` and the input topics, so the most important objects to detect should be set in the first of `input_topics` list. From a49ede7003b6e524494e788a16e7b667e701c7f1 Mon Sep 17 00:00:00 2001 From: Yuki TAKAGI <141538661+yuki-takagi-66@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:28:41 +0900 Subject: [PATCH 013/132] feat(crosswalk)!: improve stuck prevention on crosswalk (#6150) * improve algorithm * sync param Signed-off-by: Yuki Takagi --- .../config/crosswalk.param.yaml | 2 +- .../src/manager.cpp | 4 +- .../src/scene_crosswalk.cpp | 54 +++++++++---------- .../src/scene_crosswalk.hpp | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/planning/behavior_velocity_crosswalk_module/config/crosswalk.param.yaml b/planning/behavior_velocity_crosswalk_module/config/crosswalk.param.yaml index aa5dfed1e4bc5..29079b99b6718 100644 --- a/planning/behavior_velocity_crosswalk_module/config/crosswalk.param.yaml +++ b/planning/behavior_velocity_crosswalk_module/config/crosswalk.param.yaml @@ -30,7 +30,7 @@ enable_stuck_check_in_intersection: false # [-] flag to enable stuck vehicle checking for crosswalk which is in intersection stuck_vehicle_velocity: 1.0 # [m/s] threshold velocity whether other vehicles are assumed to be stuck or not. max_stuck_vehicle_lateral_offset: 2.0 # [m] The feature does not handle the vehicles farther than this value to the ego's path. - stuck_vehicle_attention_range: 10.0 # [m] Ego does not enter the crosswalk area if a stuck vehicle exists within this distance from the end of the crosswalk on the ego's path. + required_clearance: 6.0 # [m] clearance to be secured between the ego and the ahead vehicle min_acc: -1.0 # min acceleration [m/ss] min_jerk: -1.0 # min jerk [m/sss] max_jerk: 1.0 # max jerk [m/sss] diff --git a/planning/behavior_velocity_crosswalk_module/src/manager.cpp b/planning/behavior_velocity_crosswalk_module/src/manager.cpp index dc3ce32be8505..094369b0a7a3c 100644 --- a/planning/behavior_velocity_crosswalk_module/src/manager.cpp +++ b/planning/behavior_velocity_crosswalk_module/src/manager.cpp @@ -68,8 +68,8 @@ CrosswalkModuleManager::CrosswalkModuleManager(rclcpp::Node & node) getOrDeclareParameter(node, ns + ".stuck_vehicle.stuck_vehicle_velocity"); cp.max_stuck_vehicle_lateral_offset = getOrDeclareParameter(node, ns + ".stuck_vehicle.max_stuck_vehicle_lateral_offset"); - cp.stuck_vehicle_attention_range = - getOrDeclareParameter(node, ns + ".stuck_vehicle.stuck_vehicle_attention_range"); + cp.required_clearance = + getOrDeclareParameter(node, ns + ".stuck_vehicle.required_clearance"); cp.min_acc_for_stuck_vehicle = getOrDeclareParameter(node, ns + ".stuck_vehicle.min_acc"); cp.max_jerk_for_stuck_vehicle = getOrDeclareParameter(node, ns + ".stuck_vehicle.max_jerk"); diff --git a/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp b/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp index 48ae5ff03b8bd..cee6975df3155 100644 --- a/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp +++ b/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.cpp @@ -906,48 +906,48 @@ std::optional CrosswalkModule::checkStopForStuckVehicles( continue; } - const auto & obj_pos = object.kinematics.initial_pose_with_covariance.pose.position; - const auto lateral_offset = calcLateralOffset(ego_path.points, obj_pos); + const auto & obj_pose = object.kinematics.initial_pose_with_covariance.pose; + const auto lateral_offset = calcLateralOffset(ego_path.points, obj_pose.position); if (p.max_stuck_vehicle_lateral_offset < std::abs(lateral_offset)) { continue; } - const auto & ego_pos = planner_data_->current_odometry->pose.position; - const auto ego_vel = planner_data_->current_velocity->twist.linear.x; - const auto ego_acc = planner_data_->current_acceleration->accel.accel.linear.x; - - const double near_attention_range = - calcSignedArcLength(ego_path.points, ego_pos, path_intersects.back()); - const double far_attention_range = near_attention_range + p.stuck_vehicle_attention_range; - - const auto dist_ego2obj = calcSignedArcLength(ego_path.points, ego_pos, obj_pos); - - if (near_attention_range < dist_ego2obj && dist_ego2obj < far_attention_range) { - // Plan STOP considering min_acc, max_jerk and min_jerk. - const auto min_feasible_dist_ego2stop = calcDecelDistWithJerkAndAccConstraints( - ego_vel, 0.0, ego_acc, p.min_acc_for_stuck_vehicle, p.max_jerk_for_stuck_vehicle, - p.min_jerk_for_stuck_vehicle); - if (!min_feasible_dist_ego2stop) { - continue; + // check if STOP is required + const double crosswalk_front_to_obj_rear = + calcSignedArcLength(ego_path.points, path_intersects.front(), obj_pose.position) - + object.shape.dimensions.x / 2.0; + const double crosswalk_back_to_obj_rear = + calcSignedArcLength(ego_path.points, path_intersects.back(), obj_pose.position) - + object.shape.dimensions.x / 2.0; + const double required_space_length = + planner_data_->vehicle_info_.vehicle_length_m + planner_param_.required_clearance; + + if (crosswalk_front_to_obj_rear > 0.0 && crosswalk_back_to_obj_rear < required_space_length) { + // If there exists at least one vehicle ahead, plan STOP considering min_acc, max_jerk and + // min_jerk. Note that nearest search is not required because the stop pose independents to + // the vehicles. + const auto braking_distance = calcDecelDistWithJerkAndAccConstraints( + planner_data_->current_velocity->twist.linear.x, 0.0, + planner_data_->current_acceleration->accel.accel.linear.x, p.min_acc_for_stuck_vehicle, + p.max_jerk_for_stuck_vehicle, p.min_jerk_for_stuck_vehicle); + if (!braking_distance) { + return {}; } + const auto & ego_pos = planner_data_->current_odometry->pose.position; const double dist_ego2stop = calcSignedArcLength(ego_path.points, ego_pos, stop_pose->position); - const double feasible_dist_ego2stop = std::max(*min_feasible_dist_ego2stop, dist_ego2stop); + const double feasible_dist_ego2stop = std::max(*braking_distance, dist_ego2stop); const double dist_to_ego = calcSignedArcLength(ego_path.points, ego_path.points.front().point.pose.position, ego_pos); - const auto feasible_stop_pose = calcLongitudinalOffsetPose(ego_path.points, 0, dist_to_ego + feasible_dist_ego2stop); if (!feasible_stop_pose) { - continue; + return {}; } - setObjectsOfInterestData( - object.kinematics.initial_pose_with_covariance.pose, object.shape, ColorName::RED); - - // early return may not appropriate because the nearest in range object should be handled - return createStopFactor(*feasible_stop_pose, {obj_pos}); + setObjectsOfInterestData(obj_pose, object.shape, ColorName::RED); + return createStopFactor(*feasible_stop_pose, {obj_pose.position}); } } diff --git a/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp b/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp index 247907ad2dc80..ed1e342df9f7a 100644 --- a/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp +++ b/planning/behavior_velocity_crosswalk_module/src/scene_crosswalk.hpp @@ -124,7 +124,7 @@ class CrosswalkModule : public SceneModuleInterface bool enable_stuck_check_in_intersection{false}; double stuck_vehicle_velocity; double max_stuck_vehicle_lateral_offset; - double stuck_vehicle_attention_range; + double required_clearance; double min_acc_for_stuck_vehicle; double max_jerk_for_stuck_vehicle; double min_jerk_for_stuck_vehicle; From f0b85554b1e9090c982b441a0f28e0a2ffe63566 Mon Sep 17 00:00:00 2001 From: Kento Yabuuchi Date: Thu, 25 Jan 2024 19:53:29 +0900 Subject: [PATCH 014/132] chore(yabloc): rework parameters (#6170) * introduce json schema for ground_server Signed-off-by: Kento Yabuuchi * introduce json schema for ll2_decomposer Signed-off-by: Kento Yabuuchi * style(pre-commit): autofix * fix json in yabloc_common Signed-off-by: Kento Yabuuchi * introduce json schema for graph_segment Signed-off-by: Kento Yabuuchi * introduce json schema for segment_filter Signed-off-by: Kento Yabuuchi * fix yabloc_common schema.json Signed-off-by: Kento Yabuuchi * introduce json schema for undistort Signed-off-by: Kento Yabuuchi * style(pre-commit): autofix * Revert "introduce json schema for ground_server" This reverts commit 33d3e609d4e01919d11a86d3c955f53e529ae121. * Revert "introduce json schema for graph_segment" This reverts commit 00ae417f030324f2dcc7dfb4b867a969ae31aea7. Signed-off-by: Kento Yabuuchi * style(pre-commit): autofix * introduce json schema for yabloc_monitor Signed-off-by: Kento Yabuuchi * introduce json schema for yabloc_particle_filter Signed-off-by: Kento Yabuuchi * introduce json schema for yabloc_pose_initializer Signed-off-by: Kento Yabuuchi * apply pre-commit Signed-off-by: Kento Yabuuchi * fix revert conflict Signed-off-by: Kento Yabuuchi * style(pre-commit): autofix --------- Signed-off-by: Kento Yabuuchi Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- localization/yabloc/yabloc_common/README.md | 6 +- .../schema/ground_server.schema.json | 43 +++++++++ .../schema/ll2_decomposer.schema.json | 51 ++++++++++ .../yabloc/yabloc_image_processing/README.md | 15 +-- .../schema/graph_segment.schema.json | 71 ++++++++++++++ .../schema/segment_filter.schema.json | 65 +++++++++++++ .../schema/undistort.schema.json | 43 +++++++++ localization/yabloc/yabloc_monitor/README.md | 4 + .../schema/yabloc_monitor.schema.json | 33 +++++++ .../yabloc/yabloc_particle_filter/README.md | 35 +------ .../camera_particle_corrector.schema.json | 77 +++++++++++++++ .../gnss_particle_corrector.schema.json | 94 +++++++++++++++++++ .../schema/predictor.schema.json | 71 ++++++++++++++ .../yabloc/yabloc_pose_initializer/README.md | 4 +- .../camera_pose_initializer.schema.json | 33 +++++++ 15 files changed, 592 insertions(+), 53 deletions(-) create mode 100644 localization/yabloc/yabloc_common/schema/ground_server.schema.json create mode 100644 localization/yabloc/yabloc_common/schema/ll2_decomposer.schema.json create mode 100644 localization/yabloc/yabloc_image_processing/schema/graph_segment.schema.json create mode 100644 localization/yabloc/yabloc_image_processing/schema/segment_filter.schema.json create mode 100644 localization/yabloc/yabloc_image_processing/schema/undistort.schema.json create mode 100644 localization/yabloc/yabloc_monitor/schema/yabloc_monitor.schema.json create mode 100644 localization/yabloc/yabloc_particle_filter/schema/camera_particle_corrector.schema.json create mode 100644 localization/yabloc/yabloc_particle_filter/schema/gnss_particle_corrector.schema.json create mode 100644 localization/yabloc/yabloc_particle_filter/schema/predictor.schema.json create mode 100644 localization/yabloc/yabloc_pose_initializer/schema/camera_pose_initializer.schema.json diff --git a/localization/yabloc/yabloc_common/README.md b/localization/yabloc/yabloc_common/README.md index 1160f1b314b99..9ed871c6ac401 100644 --- a/localization/yabloc/yabloc_common/README.md +++ b/localization/yabloc/yabloc_common/README.md @@ -63,8 +63,4 @@ This node extracts the elements related to the road surface markings and yabloc ### Parameters -| Name | Type | Description | -| --------------------- | ---------------- | ---------------------------------------------------------------------- | -| `road_marking_labels` | vector\ | This label is used to extract the road surface markings from lanelet2. | -| `sign_board_labels` | vector\ | This label is used to extract the traffic sign boards from lanelet2. | -| `bounding_box_labels` | vector\ | This label is used to extract the bounding boxes from lanelet2. | +{{ json_to_markdown("localization/yabloc/yabloc_common/schema/ll2_decomposer.schema.json") }} diff --git a/localization/yabloc/yabloc_common/schema/ground_server.schema.json b/localization/yabloc/yabloc_common/schema/ground_server.schema.json new file mode 100644 index 0000000000000..a9b0674cedd1c --- /dev/null +++ b/localization/yabloc/yabloc_common/schema/ground_server.schema.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for ground_server", + "type": "object", + "definitions": { + "ground_server": { + "type": "object", + "properties": { + "force_zero_tilt": { + "type": "boolean", + "description": "if true, the tilt is always determined to be horizontal", + "default": false + }, + "K": { + "type": "number", + "description": "the number of neighbors for ground search on a map", + "default": 50 + }, + "R": { + "type": "number", + "description": "radius for ground search on a map [m]", + "default": 10 + } + }, + "required": ["force_zero_tilt", "K", "R"], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/ground_server" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_common/schema/ll2_decomposer.schema.json b/localization/yabloc/yabloc_common/schema/ll2_decomposer.schema.json new file mode 100644 index 0000000000000..fa5a7b37464f3 --- /dev/null +++ b/localization/yabloc/yabloc_common/schema/ll2_decomposer.schema.json @@ -0,0 +1,51 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for ll2_decomposer", + "type": "object", + "definitions": { + "ll2_decomposer": { + "type": "object", + "properties": { + "road_marking_labels": { + "type": "array", + "description": "line string types that indicating road surface markings in lanelet2", + "default": [ + "cross_walk", + "zebra_marking", + "line_thin", + "line_thick", + "pedestrian_marking", + "stop_line", + "road_border" + ] + }, + "sign_board_labels": { + "type": "array", + "description": "line string types that indicating traffic sign boards in lanelet2", + "default": ["sign-board"] + }, + "bounding_box_labels": { + "type": "array", + "description": "line string types that indicating not mapped areas in lanelet2", + "default": ["none"] + } + }, + "required": ["road_marking_labels", "sign_board_labels", "bounding_box_labels"], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/ll2_decomposer" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_image_processing/README.md b/localization/yabloc/yabloc_image_processing/README.md index 85e1d408a1b4b..921a9277a727c 100644 --- a/localization/yabloc/yabloc_image_processing/README.md +++ b/localization/yabloc/yabloc_image_processing/README.md @@ -89,14 +89,7 @@ This is a node that integrates the results of graph_segment and lsd to extract r ### Parameters -| Name | Type | Description | -| -------------------------------------- | ------ | ------------------------------------------------------------------- | -| `min_segment_length` | double | min length threshold (if it is negative, it is unlimited) | -| `max_segment_distance` | double | max distance threshold (if it is negative, it is unlimited) | -| `max_lateral_distance` | double | max lateral distance threshold (if it is negative, it is unlimited) | -| `publish_image_with_segment_for_debug` | bool | toggle whether to publish the filtered line segment for debug | -| `max_range` | double | range of debug projection visualization | -| `image_size` | int | image size of debug projection visualization | +{{ json_to_markdown("localization/yabloc/yabloc_common/schema/segment_filter.schema.json") }} ## undistort @@ -127,11 +120,7 @@ This is to avoid redundant decompression within Autoware. ### Parameters -| Name | Type | Description | -| ------------------- | ------ | ---------------------------------------------------------------------------------------------- | -| `use_sensor_qos` | bool | where to use sensor qos or not | -| `width` | int | resized image width size | -| `override_frame_id` | string | value for overriding the camera's frame_id. if blank, frame_id of static_tf is not overwritten | +{{ json_to_markdown("localization/yabloc/yabloc_common/schema/undistort.schema.json") }} #### about tf_static overriding diff --git a/localization/yabloc/yabloc_image_processing/schema/graph_segment.schema.json b/localization/yabloc/yabloc_image_processing/schema/graph_segment.schema.json new file mode 100644 index 0000000000000..c0bf96dd0de7a --- /dev/null +++ b/localization/yabloc/yabloc_image_processing/schema/graph_segment.schema.json @@ -0,0 +1,71 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for graph_segment", + "type": "object", + "definitions": { + "graph_segment": { + "type": "object", + "properties": { + "target_height_ratio": { + "type": "number", + "description": "height on the image to retrieve the candidate road surface", + "default": 0.85 + }, + "target_candidate_box_width": { + "type": "number", + "description": "size of the square area to search for candidate road surfaces", + "default": 15 + }, + "pickup_additional_graph_segment": { + "type": "boolean", + "description": "if this is true, additional regions of similar color are retrieved", + "default": true + }, + "similarity_score_threshold": { + "type": "number", + "description": "threshold for picking up additional areas", + "default": 0.8 + }, + "sigma": { + "type": "number", + "description": "parameter for cv::ximgproc::segmentation::GraphSegmentation", + "default": 0.5 + }, + "k": { + "type": "number", + "description": "parameter for cv::ximgproc::segmentation::GraphSegmentation", + "default": 300.0 + }, + "min_size": { + "type": "number", + "description": "parameter for cv::ximgproc::segmentation::GraphSegmentation", + "default": 100.0 + } + }, + "required": [ + "target_height_ratio", + "target_candidate_box_width", + "pickup_additional_graph_segment", + "similarity_score_threshold", + "sigma", + "k", + "min_size" + ], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/graph_segment" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_image_processing/schema/segment_filter.schema.json b/localization/yabloc/yabloc_image_processing/schema/segment_filter.schema.json new file mode 100644 index 0000000000000..bfe74ea80569c --- /dev/null +++ b/localization/yabloc/yabloc_image_processing/schema/segment_filter.schema.json @@ -0,0 +1,65 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for segment_filter", + "type": "object", + "definitions": { + "segment_filter": { + "type": "object", + "properties": { + "min_segment_length": { + "type": "number", + "description": "min length threshold (if it is negative, it is unlimited)", + "default": 1.5 + }, + "max_segment_distance": { + "type": "number", + "description": "max distance threshold (if it is negative, it is unlimited)", + "default": 30.0 + }, + "max_lateral_distance": { + "type": "number", + "description": "max lateral distance threshold (if it is negative, it is unlimited)", + "default": 10.0 + }, + "publish_image_with_segment_for_debug": { + "type": "boolean", + "description": "toggle whether to publish the filtered line segment for debug", + "default": true + }, + "max_range": { + "type": "number", + "description": "range of debug projection visualization", + "default": 20.0 + }, + "image_size": { + "type": "number", + "description": "image size of debug projection visualization", + "default": 800 + } + }, + "required": [ + "min_segment_length", + "max_segment_distance", + "max_lateral_distance", + "publish_image_with_segment_for_debug", + "max_range", + "image_size" + ], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/segment_filter" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_image_processing/schema/undistort.schema.json b/localization/yabloc/yabloc_image_processing/schema/undistort.schema.json new file mode 100644 index 0000000000000..d166d85024903 --- /dev/null +++ b/localization/yabloc/yabloc_image_processing/schema/undistort.schema.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for undistort", + "type": "object", + "definitions": { + "undistort": { + "type": "object", + "properties": { + "use_sensor_qos": { + "type": "boolean", + "description": "whether to use sensor qos or not", + "default": true + }, + "width": { + "type": "number", + "description": "resized image width size", + "default": 800 + }, + "override_frame_id": { + "type": "string", + "description": "value for overriding the camera's frame_id. if blank, frame_id of static_tf is not overwritten", + "default": "" + } + }, + "required": ["use_sensor_qos", "width", "override_frame_id"], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/undistort" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_monitor/README.md b/localization/yabloc/yabloc_monitor/README.md index ed4cdc36b6ba0..849429290b427 100644 --- a/localization/yabloc/yabloc_monitor/README.md +++ b/localization/yabloc/yabloc_monitor/README.md @@ -25,3 +25,7 @@ To be added, | Name | Type | Description | | -------------- | --------------------------------- | ------------------- | | `/diagnostics` | `diagnostic_msgs/DiagnosticArray` | Diagnostics outputs | + +### Parameters + +{{ json_to_markdown("localization/yabloc/yabloc_monitor/schema/yabloc_monitor.schema.json") }} diff --git a/localization/yabloc/yabloc_monitor/schema/yabloc_monitor.schema.json b/localization/yabloc/yabloc_monitor/schema/yabloc_monitor.schema.json new file mode 100644 index 0000000000000..c83a9d3ac45f3 --- /dev/null +++ b/localization/yabloc/yabloc_monitor/schema/yabloc_monitor.schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for yabloc_monitor", + "type": "object", + "definitions": { + "yabloc_monitor": { + "type": "object", + "properties": { + "availability/timestamp_tolerance": { + "type": "number", + "description": "tolerable time difference between current time and latest estimated pose", + "default": 1.0 + } + }, + "required": ["availability/timestamp_tolerance"], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/yabloc_monitor" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_particle_filter/README.md b/localization/yabloc/yabloc_particle_filter/README.md index d42ce4647bc95..f46a363102c8b 100644 --- a/localization/yabloc/yabloc_particle_filter/README.md +++ b/localization/yabloc/yabloc_particle_filter/README.md @@ -36,15 +36,7 @@ This package contains some executable nodes related to particle filter. ### Parameters -| Name | Type | Description | -| ----------------------------- | ---------------- | ----------------------------------------------------------------- | -| `visualize` | bool | whether particles are also published in visualization_msgs or not | -| `static_linear_covariance` | double | to override the covariance of `/twist_with_covariance` | -| `static_angular_covariance` | double | to override the covariance of `/twist_with_covariance` | -| `resampling_interval_seconds` | double | the interval of particle resampling | -| `num_of_particles` | int | the number of particles | -| `prediction_rate` | double | frequency of forecast updates, in Hz | -| `cov_xx_yy` | vector\ | the covariance of initial pose | +{{ json_to_markdown("localization/yabloc/yabloc_particle_filter/schema/predictor.schema.json") }} ### Services @@ -80,19 +72,7 @@ This package contains some executable nodes related to particle filter. ### Parameters -| Name | Type | Description | -| -------------------------------- | ------ | ---------------------------------------------------------------------------------------- | -| `acceptable_max_delay` | double | how long to hold the predicted particles | -| `visualize` | double | whether publish particles as marker_array or not | -| `mahalanobis_distance_threshold` | double | if the Mahalanobis distance to the GNSS for particle exceeds this, the correction skips. | -| `for_fixed/max_weight` | bool | parameter for gnss weight distribution | -| `for_fixed/flat_radius` | bool | parameter for gnss weight distribution | -| `for_fixed/max_radius` | bool | parameter for gnss weight distribution | -| `for_fixed/min_weight` | bool | parameter for gnss weight distribution | -| `for_not_fixed/flat_radius` | bool | parameter for gnss weight distribution | -| `for_not_fixed/max_radius` | bool | parameter for gnss weight distribution | -| `for_not_fixed/min_weight` | bool | parameter for gnss weight distribution | -| `for_not_fixed/max_weight` | bool | parameter for gnss weight distribution | +{{ json_to_markdown("localization/yabloc/yabloc_particle_filter/schema/gnss_particle_corrector.schema.json") }} ## camera_particle_corrector @@ -127,16 +107,7 @@ This package contains some executable nodes related to particle filter. ### Parameters -| Name | Type | Description | -| ---------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `acceptable_max_delay` | double | how long to hold the predicted particles | -| `visualize` | double | whether publish particles as marker_array or not | -| `image_size` | int | image size of debug/cost_map_image | -| `max_range` | double | width of hierarchical cost map | -| `gamma` | double | gamma value of the intensity gradient of the cost map | -| `min_prob` | double | minimum particle weight the corrector node gives | -| `far_weight_gain` | double | `exp(-far_weight_gain_ * squared_distance_from_camera)` is weight gain. if this is large, the nearby road markings will be more important | -| `enabled_at_first` | bool | if it is false, this node is not activated at first. you can activate by service call | +{{ json_to_markdown("localization/yabloc/yabloc_particle_filter/schema/camera_particle_corrector.schema.json") }} ### Services diff --git a/localization/yabloc/yabloc_particle_filter/schema/camera_particle_corrector.schema.json b/localization/yabloc/yabloc_particle_filter/schema/camera_particle_corrector.schema.json new file mode 100644 index 0000000000000..a8b4873347f52 --- /dev/null +++ b/localization/yabloc/yabloc_particle_filter/schema/camera_particle_corrector.schema.json @@ -0,0 +1,77 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for camera_particle_corrector", + "type": "object", + "definitions": { + "camera_particle_corrector": { + "type": "object", + "properties": { + "acceptable_max_delay": { + "type": "number", + "description": "how long to hold the predicted particles", + "default": 1.0 + }, + "visualize": { + "type": "boolean", + "description": "whether publish particles as marker_array or not", + "default": false + }, + "image_size": { + "type": "number", + "description": "image size of debug/cost_map_image", + "default": 800 + }, + "max_range": { + "type": "number", + "description": "width of hierarchical cost map", + "default": 40.0 + }, + "gamma": { + "type": "number", + "description": "gamma value of the intensity gradient of the cost map", + "default": 5.0 + }, + "min_prob": { + "type": "number", + "description": "minimum particle weight the corrector node gives", + "default": 0.1 + }, + "far_weight_gain": { + "type": "number", + "description": "`exp(-far_weight_gain_ * squared_distance_from_camera)` is weight gain. if this is large, the nearby road markings will be more important", + "default": 0.001 + }, + "enabled_at_first": { + "type": "boolean", + "description": "if it is false, this node is not activated at first. you can activate by service call", + "default": true + } + }, + "required": [ + "acceptable_max_delay", + "visualize", + "image_size", + "max_range", + "gamma", + "min_prob", + "far_weight_gain", + "enabled_at_first" + ], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/camera_particle_corrector" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_particle_filter/schema/gnss_particle_corrector.schema.json b/localization/yabloc/yabloc_particle_filter/schema/gnss_particle_corrector.schema.json new file mode 100644 index 0000000000000..a3990ad333981 --- /dev/null +++ b/localization/yabloc/yabloc_particle_filter/schema/gnss_particle_corrector.schema.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for gnss_particle_corrector", + "type": "object", + "definitions": { + "gnss_particle_corrector": { + "type": "object", + "properties": { + "acceptable_max_delay": { + "type": "number", + "description": "how long to hold the predicted particles", + "default": 1.0 + }, + "visualize": { + "type": "boolean", + "description": "whether publish particles as marker_array or not", + "default": false + }, + "mahalanobis_distance_threshold": { + "type": "number", + "description": "if the Mahalanobis distance to the GNSS for particle exceeds this, the correction skips.", + "default": 30.0 + }, + "for_fixed/max_weight": { + "type": "number", + "description": "gnss weight distribution used when observation is fixed", + "default": 5.0 + }, + "for_fixed/flat_radius": { + "type": "number", + "description": "gnss weight distribution used when observation is fixed", + "default": 0.5 + }, + "for_fixed/max_radius": { + "type": "number", + "description": "gnss weight distribution used when observation is fixed", + "default": 10.0 + }, + "for_fixed/min_weight": { + "type": "number", + "description": "gnss weight distribution used when observation is fixed", + "default": 0.5 + }, + "for_not_fixed/max_weight": { + "type": "number", + "description": "gnss weight distribution used when observation is not fixed", + "default": 1.0 + }, + "for_not_fixed/flat_radius": { + "type": "number", + "description": "gnss weight distribution used when observation is not fixed", + "default": 5.0 + }, + "for_not_fixed/max_radius": { + "type": "number", + "description": "gnss weight distribution used when observation is not fixed", + "default": 20.0 + }, + "for_not_fixed/min_weight": { + "type": "number", + "description": "gnss weight distribution used when observation is not fixed", + "default": 0.5 + } + }, + "required": [ + "acceptable_max_delay", + "visualize", + "for_fixed/max_weight", + "for_fixed/flat_radius", + "for_fixed/max_radius", + "for_fixed/min_weight", + "for_not_fixed/max_weight", + "for_not_fixed/flat_radius", + "for_not_fixed/max_radius", + "for_not_fixed/min_weight" + ], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/gnss_particle_corrector" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_particle_filter/schema/predictor.schema.json b/localization/yabloc/yabloc_particle_filter/schema/predictor.schema.json new file mode 100644 index 0000000000000..487dffdb00094 --- /dev/null +++ b/localization/yabloc/yabloc_particle_filter/schema/predictor.schema.json @@ -0,0 +1,71 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for predictor", + "type": "object", + "definitions": { + "predictor": { + "type": "object", + "properties": { + "visualize": { + "type": "boolean", + "description": "whether particles are also published in visualization_msgs or not", + "default": true + }, + "static_linear_covariance": { + "type": "number", + "description": "overriding covariance of `/twist_with_covariance`", + "default": 0.04 + }, + "static_angular_covariance": { + "type": "number", + "description": "overriding covariance of `/twist_with_covariance`", + "default": 0.006 + }, + "resampling_interval_seconds": { + "type": "number", + "description": "the interval of particle resampling", + "default": 1.0 + }, + "num_of_particles": { + "type": "number", + "description": "the number of particles", + "default": 500 + }, + "prediction_rate": { + "type": "number", + "description": "frequency of forecast updates, in Hz", + "default": 50.0 + }, + "cov_xx_yy": { + "type": "array", + "description": "the covariance of initial pose", + "default": [2.0, 0.25] + } + }, + "required": [ + "visualize", + "static_linear_covariance", + "static_angular_covariance", + "resampling_interval_seconds", + "num_of_particles", + "prediction_rate", + "cov_xx_yy" + ], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/predictor" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} diff --git a/localization/yabloc/yabloc_pose_initializer/README.md b/localization/yabloc/yabloc_pose_initializer/README.md index 907b79c1459ec..33b9788cca3d3 100644 --- a/localization/yabloc/yabloc_pose_initializer/README.md +++ b/localization/yabloc/yabloc_pose_initializer/README.md @@ -59,9 +59,7 @@ Converted model URL ### Parameters -| Name | Type | Description | -| ------------------ | ---- | ----------------------------------------- | -| `angle_resolution` | int | how many divisions of 1 sigma angle range | +{{ json_to_markdown("localization/yabloc/yabloc_pose_initializer/schema/camera_pose_initializer.schema.json") }} ### Services diff --git a/localization/yabloc/yabloc_pose_initializer/schema/camera_pose_initializer.schema.json b/localization/yabloc/yabloc_pose_initializer/schema/camera_pose_initializer.schema.json new file mode 100644 index 0000000000000..26a53e0fe408f --- /dev/null +++ b/localization/yabloc/yabloc_pose_initializer/schema/camera_pose_initializer.schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Parameters for camera_pose_initializer", + "type": "object", + "definitions": { + "camera_pose_initializer": { + "type": "object", + "properties": { + "angle_resolution": { + "type": "number", + "description": "how many divisions of 1 sigma angle range", + "default": 30 + } + }, + "required": ["angle_resolution"], + "additionalProperties": false + } + }, + "properties": { + "/**": { + "type": "object", + "properties": { + "ros__parameters": { + "$ref": "#/definitions/camera_pose_initializer" + } + }, + "required": ["ros__parameters"], + "additionalProperties": false + } + }, + "required": ["/**"], + "additionalProperties": false +} From 058ccd3eb5417284fbb5e1cdd1d1fa2e6c0c6b38 Mon Sep 17 00:00:00 2001 From: Yuki TAKAGI <141538661+yuki-takagi-66@users.noreply.github.com> Date: Fri, 26 Jan 2024 12:48:53 +0900 Subject: [PATCH 015/132] docs(crosswalk): update docs (#6177) * update docs Signed-off-by: Yuki Takagi --- .../README.md | 2 +- .../docs/stuck_vehicle_detection.svg | 111 +++++++++--------- 2 files changed, 57 insertions(+), 56 deletions(-) diff --git a/planning/behavior_velocity_crosswalk_module/README.md b/planning/behavior_velocity_crosswalk_module/README.md index ce231659ccf78..c1ddc28e03426 100644 --- a/planning/behavior_velocity_crosswalk_module/README.md +++ b/planning/behavior_velocity_crosswalk_module/README.md @@ -196,7 +196,7 @@ In the `stuck_vehicle` namespace, the following parameters are defined. | ---------------------------------- | ------- | ------ | ----------------------------------------------------------------------- | | `stuck_vehicle_velocity` | [m/s] | double | maximum velocity threshold whether the target vehicle is stopped or not | | `max_stuck_vehicle_lateral_offset` | [m] | double | maximum lateral offset of the target vehicle position | -| `stuck_vehicle_attention_range` | [m] | double | detection area length ahead of the crosswalk | +| `required_clearance` | [m] | double | clearance to be secured between the ego and the ahead vehicle | | `min_acc` | [m/ss] | double | minimum acceleration to stop | | `min_jerk` | [m/sss] | double | minimum jerk to stop | | `max_jerk` | [m/sss] | double | maximum jerk to stop | diff --git a/planning/behavior_velocity_crosswalk_module/docs/stuck_vehicle_detection.svg b/planning/behavior_velocity_crosswalk_module/docs/stuck_vehicle_detection.svg index c517be5bb9967..773edf7989de9 100644 --- a/planning/behavior_velocity_crosswalk_module/docs/stuck_vehicle_detection.svg +++ b/planning/behavior_velocity_crosswalk_module/docs/stuck_vehicle_detection.svg @@ -1,92 +1,93 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
+
-
- stuck_vehicle_attention_range +
+ vehicle_length+required_clearance
- stuck_vehicle_atten... + vehicle_length+required_clearance - - - - - - - - - + + + + + + + + + + -
+
-
+
max_stuck_vehicle_lateral_offset
- max_stuck_vehicle_l... + max_stuck_vehicle_lateral_offset - - + + - + Text is not SVG - cannot display From ccd852b381cbd5f37420dd1c06cf7ee9ae929ae2 Mon Sep 17 00:00:00 2001 From: Kosuke Takeuchi Date: Fri, 26 Jan 2024 12:54:55 +0900 Subject: [PATCH 016/132] fix(dynamic_avoidance_planner): inherit modified goal (#6179) Signed-off-by: kosuke55 --- planning/behavior_path_dynamic_avoidance_module/src/scene.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/planning/behavior_path_dynamic_avoidance_module/src/scene.cpp b/planning/behavior_path_dynamic_avoidance_module/src/scene.cpp index b43102ecbd16d..73cabd00592a8 100644 --- a/planning/behavior_path_dynamic_avoidance_module/src/scene.cpp +++ b/planning/behavior_path_dynamic_avoidance_module/src/scene.cpp @@ -397,6 +397,7 @@ BehaviorModuleOutput DynamicAvoidanceModule::plan() current_drivable_area_info, getPreviousModuleOutput().drivable_area_info); output.reference_path = getPreviousModuleOutput().reference_path; output.turn_signal_info = getPreviousModuleOutput().turn_signal_info; + output.modified_goal = getPreviousModuleOutput().modified_goal; return output; } From 57cf88d2b85db000ad19ff195eb4106283367edf Mon Sep 17 00:00:00 2001 From: Kyoichi Sugahara Date: Fri, 26 Jan 2024 16:03:48 +0900 Subject: [PATCH 017/132] fix(start_planner): update drivable area info and enable idle to running state transition (#6172) Update drivable area info and enable idle to running state transition Signed-off-by: kyoichi-sugahara --- .../utils/drivable_area_expansion/static_drivable_area.cpp | 4 ++++ .../start_planner_module.hpp | 2 +- .../src/start_planner_module.cpp | 6 +----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp b/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp index 03fae6864fe50..4e25e9257ddfd 100644 --- a/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp +++ b/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp @@ -1884,6 +1884,10 @@ DrivableAreaInfo combineDrivableAreaInfo( drivable_area_info1.enable_expanding_intersection_areas || drivable_area_info2.enable_expanding_intersection_areas; + // drivable margin + combined_drivable_area_info.drivable_margin = + std::max(drivable_area_info1.drivable_margin, drivable_area_info2.drivable_margin); + return combined_drivable_area_info; } diff --git a/planning/behavior_path_start_planner_module/include/behavior_path_start_planner_module/start_planner_module.hpp b/planning/behavior_path_start_planner_module/include/behavior_path_start_planner_module/start_planner_module.hpp index 5bbde1c2fc523..cffce8218c554 100644 --- a/planning/behavior_path_start_planner_module/include/behavior_path_start_planner_module/start_planner_module.hpp +++ b/planning/behavior_path_start_planner_module/include/behavior_path_start_planner_module/start_planner_module.hpp @@ -139,7 +139,7 @@ class StartPlannerModule : public SceneModuleInterface bool canTransitFailureState() override { return false; } - bool canTransitIdleToRunningState() override; + bool canTransitIdleToRunningState() override { return true; } /** * @brief init member variables. diff --git a/planning/behavior_path_start_planner_module/src/start_planner_module.cpp b/planning/behavior_path_start_planner_module/src/start_planner_module.cpp index 6c9000caac956..8937c8a837694 100644 --- a/planning/behavior_path_start_planner_module/src/start_planner_module.cpp +++ b/planning/behavior_path_start_planner_module/src/start_planner_module.cpp @@ -347,11 +347,6 @@ bool StartPlannerModule::canTransitSuccessState() return hasFinishedPullOut(); } -bool StartPlannerModule::canTransitIdleToRunningState() -{ - return isActivated() && !isWaitingApproval(); -} - BehaviorModuleOutput StartPlannerModule::plan() { if (isWaitingApproval()) { @@ -1317,6 +1312,7 @@ bool StartPlannerModule::planFreespacePath() void StartPlannerModule::setDrivableAreaInfo(BehaviorModuleOutput & output) const { if (status_.planner_type == PlannerType::FREESPACE) { + std::cerr << "Freespace planner updated drivable area." << std::endl; const double drivable_area_margin = planner_data_->parameters.vehicle_width; output.drivable_area_info.drivable_margin = planner_data_->parameters.vehicle_width / 2.0 + drivable_area_margin; From dc0184fd540dbd030f6d93d0fa7ff6b91469110b Mon Sep 17 00:00:00 2001 From: kminoda <44218668+kminoda@users.noreply.github.com> Date: Fri, 26 Jan 2024 21:47:48 +0900 Subject: [PATCH 018/132] chore(cluster_merger): rework parameters (#6165) chore(cluster_merger): organize parameter Signed-off-by: kminoda --- perception/cluster_merger/CMakeLists.txt | 1 + perception/cluster_merger/config/cluster_merger.param.yaml | 3 +++ perception/cluster_merger/launch/cluster_merger.launch.xml | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 perception/cluster_merger/config/cluster_merger.param.yaml diff --git a/perception/cluster_merger/CMakeLists.txt b/perception/cluster_merger/CMakeLists.txt index 49506f4b439fb..5ad0de572b44f 100644 --- a/perception/cluster_merger/CMakeLists.txt +++ b/perception/cluster_merger/CMakeLists.txt @@ -24,4 +24,5 @@ endif() ament_auto_package( INSTALL_TO_SHARE launch + config ) diff --git a/perception/cluster_merger/config/cluster_merger.param.yaml b/perception/cluster_merger/config/cluster_merger.param.yaml new file mode 100644 index 0000000000000..adca6c203282f --- /dev/null +++ b/perception/cluster_merger/config/cluster_merger.param.yaml @@ -0,0 +1,3 @@ +/**: + ros__parameters: + output_frame_id: "base_link" diff --git a/perception/cluster_merger/launch/cluster_merger.launch.xml b/perception/cluster_merger/launch/cluster_merger.launch.xml index 1bbd0ebd91e12..f0f90efe051a0 100644 --- a/perception/cluster_merger/launch/cluster_merger.launch.xml +++ b/perception/cluster_merger/launch/cluster_merger.launch.xml @@ -3,12 +3,12 @@ - + - + From 34a7c2dfcb1e11b67b22787303dc287af7dc675d Mon Sep 17 00:00:00 2001 From: Motz <83898149+Motsu-san@users.noreply.github.com> Date: Sat, 27 Jan 2024 01:19:15 +0900 Subject: [PATCH 019/132] refactor(localization_error_monitor): rename localization_accuracy (#5178) refactor: Rename localization_accuracy to localization_error_ellipse Signed-off-by: Motsu-san --- localization/localization_error_monitor/src/diagnostics.cpp | 4 ++-- simulator/fault_injection/config/fault_injection.param.yaml | 2 +- .../config/diagnostic_aggregator/localization.param.yaml | 4 ++-- .../config/system_error_monitor.param.yaml | 2 +- .../system_error_monitor.planning_simulation.param.yaml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/localization/localization_error_monitor/src/diagnostics.cpp b/localization/localization_error_monitor/src/diagnostics.cpp index 0c5a4a7800639..375fccfa06787 100644 --- a/localization/localization_error_monitor/src/diagnostics.cpp +++ b/localization/localization_error_monitor/src/diagnostics.cpp @@ -23,7 +23,7 @@ diagnostic_msgs::msg::DiagnosticStatus checkLocalizationAccuracy( diagnostic_msgs::msg::DiagnosticStatus stat; diagnostic_msgs::msg::KeyValue key_value; - key_value.key = "localization_accuracy"; + key_value.key = "localization_error_ellipse"; key_value.value = std::to_string(ellipse_size); stat.values.push_back(key_value); @@ -47,7 +47,7 @@ diagnostic_msgs::msg::DiagnosticStatus checkLocalizationAccuracyLateralDirection diagnostic_msgs::msg::DiagnosticStatus stat; diagnostic_msgs::msg::KeyValue key_value; - key_value.key = "localization_accuracy_lateral_direction"; + key_value.key = "localization_error_ellipse_lateral_direction"; key_value.value = std::to_string(ellipse_size); stat.values.push_back(key_value); diff --git a/simulator/fault_injection/config/fault_injection.param.yaml b/simulator/fault_injection/config/fault_injection.param.yaml index 1a57b852f7361..ac02442d70b4d 100644 --- a/simulator/fault_injection/config/fault_injection.param.yaml +++ b/simulator/fault_injection/config/fault_injection.param.yaml @@ -4,7 +4,7 @@ vehicle_is_out_of_lane: "lane_departure" trajectory_deviation_is_high: "trajectory_deviation" localization_matching_score_is_low: "ndt_scan_matcher" - localization_accuracy_is_low: "localization_accuracy" + localization_accuracy_is_low: "localization_error_ellipse" map_version_is_different: "map_version" trajectory_is_invalid: "trajectory_point_validation" cpu_temperature_is_high: "CPU Temperature" diff --git a/system/system_error_monitor/config/diagnostic_aggregator/localization.param.yaml b/system/system_error_monitor/config/diagnostic_aggregator/localization.param.yaml index 55af6ab2d2c55..9ed82304036cc 100644 --- a/system/system_error_monitor/config/diagnostic_aggregator/localization.param.yaml +++ b/system/system_error_monitor/config/diagnostic_aggregator/localization.param.yaml @@ -24,9 +24,9 @@ contains: ["ndt_scan_matcher"] timeout: 1.0 - localization_accuracy: + localization_error_ellipse: type: diagnostic_aggregator/GenericAnalyzer - path: localization_accuracy + path: localization_error_ellipse contains: ["localization: localization_error_monitor"] timeout: 1.0 diff --git a/system/system_error_monitor/config/system_error_monitor.param.yaml b/system/system_error_monitor/config/system_error_monitor.param.yaml index 1778f6594f0c3..2b58f5b42c0be 100644 --- a/system/system_error_monitor/config/system_error_monitor.param.yaml +++ b/system/system_error_monitor/config/system_error_monitor.param.yaml @@ -24,7 +24,7 @@ /autoware/localization/node_alive_monitoring: default /autoware/localization/performance_monitoring/matching_score: { sf_at: "warn", lf_at: "none", spf_at: "none" } - /autoware/localization/performance_monitoring/localization_accuracy: default + /autoware/localization/performance_monitoring/localization_error_ellipse: default /autoware/map/node_alive_monitoring: default diff --git a/system/system_error_monitor/config/system_error_monitor.planning_simulation.param.yaml b/system/system_error_monitor/config/system_error_monitor.planning_simulation.param.yaml index 9784259490ec2..f1031444394d0 100644 --- a/system/system_error_monitor/config/system_error_monitor.planning_simulation.param.yaml +++ b/system/system_error_monitor/config/system_error_monitor.planning_simulation.param.yaml @@ -24,7 +24,7 @@ /autoware/localization/node_alive_monitoring: default # /autoware/localization/performance_monitoring/matching_score: { sf_at: "warn", lf_at: "none", spf_at: "none" } - # /autoware/localization/performance_monitoring/localization_accuracy: default + # /autoware/localization/performance_monitoring/localization_error_ellipse: default /autoware/map/node_alive_monitoring: default From 0a057e12d4dfdae0e8a5afcd88805581047db931 Mon Sep 17 00:00:00 2001 From: Kosuke Takeuchi Date: Sat, 27 Jan 2024 01:59:51 +0900 Subject: [PATCH 020/132] fix(behavior_path_planner): sort keep last modules considering priority (#6174) Signed-off-by: kosuke55 --- .../src/planner_manager.cpp | 67 +++++++++++++------ 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/planning/behavior_path_planner/src/planner_manager.cpp b/planning/behavior_path_planner/src/planner_manager.cpp index cbcec2e3095d3..4caf5683f3982 100644 --- a/planning/behavior_path_planner/src/planner_manager.cpp +++ b/planning/behavior_path_planner/src/planner_manager.cpp @@ -630,32 +630,38 @@ BehaviorModuleOutput PlannerManager::runApprovedModules(const std::shared_ptrisKeepLast(); + const auto get_sorted_keep_last_modules = [this](const auto & modules) { + std::vector keep_last_modules; + + std::copy_if( + modules.begin(), modules.end(), std::back_inserter(keep_last_modules), + [this](const auto & m) { return getManager(m)->isKeepLast(); }); + + // sort by priority (low -> high) + std::sort( + keep_last_modules.begin(), keep_last_modules.end(), [this](const auto & a, const auto & b) { + return getManager(a)->getPriority() < getManager(b)->getPriority(); + }); + + return keep_last_modules; }; - move_to_end(approved_module_ptrs_, keep_last_module_cond); + + for (const auto & module : get_sorted_keep_last_modules(approved_module_ptrs_)) { + move_to_end(approved_module_ptrs_, module); + } } // lock approved modules besides last one @@ -768,6 +774,25 @@ BehaviorModuleOutput PlannerManager::runApprovedModules(const std::shared_ptrgetCurrentStatus() == ModuleStatus::SUCCESS; }; From 29faba589fa9429501f536a54711a7ef34ba68d4 Mon Sep 17 00:00:00 2001 From: Fumiya Watanabe Date: Sat, 27 Jan 2024 03:35:54 +0900 Subject: [PATCH 021/132] refactor(lane_change): add const to lane change functions (#6175) Signed-off-by: Fumiya Watanabe --- .../include/behavior_path_lane_change_module/scene.hpp | 6 +++--- .../behavior_path_lane_change_module/utils/base_class.hpp | 6 +++--- planning/behavior_path_lane_change_module/src/scene.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp index f991ca0d849f0..8d2e3b451fe98 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/scene.hpp @@ -55,7 +55,7 @@ class NormalLaneChange : public LaneChangeBase BehaviorModuleOutput generateOutput() override; - void extendOutputDrivableArea(BehaviorModuleOutput & output) override; + void extendOutputDrivableArea(BehaviorModuleOutput & output) const override; void insertStopPoint(const lanelet::ConstLanelets & lanelets, PathWithLaneId & path) override; @@ -65,7 +65,7 @@ class NormalLaneChange : public LaneChangeBase void resetParameters() override; - TurnSignalInfo updateOutputTurnSignal() override; + TurnSignalInfo updateOutputTurnSignal() const override; bool calcAbortPath() override; @@ -141,7 +141,7 @@ class NormalLaneChange : public LaneChangeBase const utils::path_safety_checker::RSSparams rss_params, const bool is_stuck, const bool check_safety = true) const override; - TurnSignalInfo calcTurnSignalInfo() override; + TurnSignalInfo calcTurnSignalInfo() const override; bool isValidPath(const PathWithLaneId & path) const override; diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp index 400d5505dc49f..e78d706334bae 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp @@ -66,7 +66,7 @@ class LaneChangeBase virtual BehaviorModuleOutput generateOutput() = 0; - virtual void extendOutputDrivableArea(BehaviorModuleOutput & output) = 0; + virtual void extendOutputDrivableArea(BehaviorModuleOutput & output) const = 0; virtual PathWithLaneId getReferencePath() const = 0; @@ -74,7 +74,7 @@ class LaneChangeBase virtual void resetParameters() = 0; - virtual TurnSignalInfo updateOutputTurnSignal() = 0; + virtual TurnSignalInfo updateOutputTurnSignal() const = 0; virtual bool hasFinishedLaneChange() const = 0; @@ -225,7 +225,7 @@ class LaneChangeBase LaneChangePaths * candidate_paths, const utils::path_safety_checker::RSSparams rss_params, const bool is_stuck, const bool check_safety) const = 0; - virtual TurnSignalInfo calcTurnSignalInfo() = 0; + virtual TurnSignalInfo calcTurnSignalInfo() const = 0; virtual bool isValidPath(const PathWithLaneId & path) const = 0; diff --git a/planning/behavior_path_lane_change_module/src/scene.cpp b/planning/behavior_path_lane_change_module/src/scene.cpp index f5100f16129c2..b115ab7c163c0 100644 --- a/planning/behavior_path_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_lane_change_module/src/scene.cpp @@ -183,7 +183,7 @@ BehaviorModuleOutput NormalLaneChange::generateOutput() return output; } -void NormalLaneChange::extendOutputDrivableArea(BehaviorModuleOutput & output) +void NormalLaneChange::extendOutputDrivableArea(BehaviorModuleOutput & output) const { const auto & dp = planner_data_->drivable_area_expansion_parameters; @@ -431,7 +431,7 @@ void NormalLaneChange::resetParameters() RCLCPP_DEBUG(logger_, "reset all flags and debug information."); } -TurnSignalInfo NormalLaneChange::updateOutputTurnSignal() +TurnSignalInfo NormalLaneChange::updateOutputTurnSignal() const { TurnSignalInfo turn_signal_info = calcTurnSignalInfo(); const auto [turn_signal_command, distance_to_vehicle_front] = utils::getPathTurnSignal( @@ -1447,7 +1447,7 @@ PathSafetyStatus NormalLaneChange::isApprovedPathSafe() const return safety_status; } -TurnSignalInfo NormalLaneChange::calcTurnSignalInfo() +TurnSignalInfo NormalLaneChange::calcTurnSignalInfo() const { const auto get_blinker_pose = [](const PathWithLaneId & path, const double length) { double accumulated_length = 0.0; From 16ba2d76b5b44c7b3e3e954b1f72f0ff266aac47 Mon Sep 17 00:00:00 2001 From: Kento Yabuuchi Date: Sat, 27 Jan 2024 03:54:59 +0900 Subject: [PATCH 022/132] chore(yabloc): replace parameters by json_to_markdown in readme (#6183) * replace parameters by json_to_markdown Signed-off-by: Kento Yabuuchi * fix some schma path Signed-off-by: Kento Yabuuchi * fix again Signed-off-by: Kento Yabuuchi --------- Signed-off-by: Kento Yabuuchi --- localization/yabloc/yabloc_common/README.md | 6 +----- .../yabloc/yabloc_image_processing/README.md | 14 +++----------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/localization/yabloc/yabloc_common/README.md b/localization/yabloc/yabloc_common/README.md index 9ed871c6ac401..6368305bdbfad 100644 --- a/localization/yabloc/yabloc_common/README.md +++ b/localization/yabloc/yabloc_common/README.md @@ -32,11 +32,7 @@ It estimates the height and tilt of the ground from lanelet2. ### Parameters -| Name | Type | Description | -| ----------------- | ---- | -------------------------------------------------------- | -| `force_zero_tilt` | bool | if true, the tilt is always determined to be horizontal. | -| `K` | int | parameter for nearest k search | -| `R` | int | parameter for radius search | +{{ json_to_markdown("localization/yabloc/yabloc_common/schema/ground_server.schema.json") }} ## ll2_decomposer diff --git a/localization/yabloc/yabloc_image_processing/README.md b/localization/yabloc/yabloc_image_processing/README.md index 921a9277a727c..9816a02c48121 100644 --- a/localization/yabloc/yabloc_image_processing/README.md +++ b/localization/yabloc/yabloc_image_processing/README.md @@ -53,15 +53,7 @@ This node extract road surface region by [graph-based-segmentation](https://docs ### Parameters -| Name | Type | Description | -| --------------------------------- | ------ | ------------------------------------------------------------------ | -| `target_height_ratio` | double | height on the image to retrieve the candidate road surface | -| `target_candidate_box_width` | int | size of the square area to search for candidate road surfaces | -| `pickup_additional_graph_segment` | bool | if this is true, additional regions of similar color are retrieved | -| `similarity_score_threshold` | double | threshold for picking up additional areas | -| `sigma` | double | parameters for cv::ximgproc::segmentation | -| `k` | double | parameters for cv::ximgproc::segmentation | -| `min_size` | double | parameters for cv::ximgproc::segmentation | +{{ json_to_markdown("localization/yabloc/yabloc_image_processing/schema/graph_segment.schema.json") }} ## segment_filter @@ -89,7 +81,7 @@ This is a node that integrates the results of graph_segment and lsd to extract r ### Parameters -{{ json_to_markdown("localization/yabloc/yabloc_common/schema/segment_filter.schema.json") }} +{{ json_to_markdown("localization/yabloc/yabloc_image_processing/schema/segment_filter.schema.json") }} ## undistort @@ -120,7 +112,7 @@ This is to avoid redundant decompression within Autoware. ### Parameters -{{ json_to_markdown("localization/yabloc/yabloc_common/schema/undistort.schema.json") }} +{{ json_to_markdown("localization/yabloc/yabloc_image_processing/schema/undistort.schema.json") }} #### about tf_static overriding From 70226203197b30a0445725657694487da43abaf0 Mon Sep 17 00:00:00 2001 From: Fumiya Watanabe Date: Sat, 27 Jan 2024 05:56:26 +0900 Subject: [PATCH 023/132] chore(motion_velocity_smoother): add maintainer (#6184) Signed-off-by: Fumiya Watanabe --- planning/motion_velocity_smoother/package.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/planning/motion_velocity_smoother/package.xml b/planning/motion_velocity_smoother/package.xml index 4bb0d8a2883dd..9792aa2bdd60b 100644 --- a/planning/motion_velocity_smoother/package.xml +++ b/planning/motion_velocity_smoother/package.xml @@ -8,6 +8,7 @@ Fumiya Watanabe Takamasa Horibe Makoto Kurihara + Satoshi Ota Apache License 2.0 Takamasa Horibe From 01fdac086484e90b960644a3cdf05ffd974ec8c4 Mon Sep 17 00:00:00 2001 From: Kosuke Takeuchi Date: Sat, 27 Jan 2024 11:38:35 +0900 Subject: [PATCH 024/132] feat(goal_planner): consider moving objects when deciding path (#6178) feat(goal_planner): consider move objects when deciding path Signed-off-by: kosuke55 --- .../goal_planner_module.hpp | 2 +- .../src/goal_planner_module.cpp | 53 +++++++++++++------ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/planning/behavior_path_goal_planner_module/include/behavior_path_goal_planner_module/goal_planner_module.hpp b/planning/behavior_path_goal_planner_module/include/behavior_path_goal_planner_module/goal_planner_module.hpp index 51638e5485fe2..2c839f582be12 100644 --- a/planning/behavior_path_goal_planner_module/include/behavior_path_goal_planner_module/goal_planner_module.hpp +++ b/planning/behavior_path_goal_planner_module/include/behavior_path_goal_planner_module/goal_planner_module.hpp @@ -419,7 +419,7 @@ class GoalPlannerModule : public SceneModuleInterface bool checkOccupancyGridCollision(const PathWithLaneId & path) const; bool checkObjectsCollision( const PathWithLaneId & path, const double collision_check_margin, - const bool update_debug_data = false) const; + const bool extract_static_objects, const bool update_debug_data = false) const; // goal seach Pose calcRefinedGoal(const Pose & goal_pose) const; diff --git a/planning/behavior_path_goal_planner_module/src/goal_planner_module.cpp b/planning/behavior_path_goal_planner_module/src/goal_planner_module.cpp index faa9e28e28b3b..00810432a6f82 100644 --- a/planning/behavior_path_goal_planner_module/src/goal_planner_module.cpp +++ b/planning/behavior_path_goal_planner_module/src/goal_planner_module.cpp @@ -624,7 +624,9 @@ bool GoalPlannerModule::canReturnToLaneParking() if ( parameters_->use_object_recognition && - checkObjectsCollision(path, parameters_->object_recognition_collision_check_margin)) { + checkObjectsCollision( + path, parameters_->object_recognition_collision_check_margin, + /*extract_static_objects=*/false)) { return false; } @@ -711,7 +713,9 @@ std::vector GoalPlannerModule::sortPullOverPathCandidatesByGoalPri const auto resampled_path = utils::resamplePathWithSpline(pull_over_path.getParkingPath(), 0.5); for (const auto & scale_factor : scale_factors) { - if (!checkObjectsCollision(resampled_path, margin * scale_factor)) { + if (!checkObjectsCollision( + resampled_path, margin * scale_factor, + /*extract_static_objects=*/true)) { return margin * scale_factor; } } @@ -771,8 +775,10 @@ std::optional> GoalPlannerModule::selectP const auto resampled_path = utils::resamplePathWithSpline(pull_over_path.getParkingPath(), 0.5); if ( - parameters_->use_object_recognition && - checkObjectsCollision(resampled_path, collision_check_margin, true /*update_debug_data*/)) { + parameters_->use_object_recognition && checkObjectsCollision( + resampled_path, collision_check_margin, + /*extract_static_objects=*/true, + /*update_debug_data=*/true)) { continue; } @@ -914,6 +920,7 @@ bool GoalPlannerModule::hasNotDecidedPath() const DecidingPathStatusWithStamp GoalPlannerModule::checkDecidingPathStatus() const { const auto & prev_status = prev_data_.deciding_path_status; + const bool enable_safety_check = parameters_->safety_check_params.enable_safety_check; // Once this function returns true, it will continue to return true thereafter if (prev_status.first == DecidingPathStatus::DECIDED) { @@ -927,8 +934,7 @@ DecidingPathStatusWithStamp GoalPlannerModule::checkDecidingPathStatus() const // If it is dangerous against dynamic objects before approval, do not determine the path. // This eliminates a unsafe path to be approved - if ( - parameters_->safety_check_params.enable_safety_check && !isSafePath().first && !isActivated()) { + if (enable_safety_check && !isSafePath().first && !isActivated()) { RCLCPP_DEBUG( getLogger(), "[DecidingPathStatus]: NOT_DECIDED. path is not safe against dynamic objects before " @@ -957,13 +963,20 @@ DecidingPathStatusWithStamp GoalPlannerModule::checkDecidingPathStatus() const const auto parking_path = utils::resamplePathWithSpline(pull_over_path->getParkingPath(), 0.5); const double margin = parameters_->object_recognition_collision_check_margin * hysteresis_factor; - if (checkObjectsCollision(parking_path, margin)) { + if (checkObjectsCollision(parking_path, margin, /*extract_static_objects=*/false)) { RCLCPP_DEBUG( getLogger(), "[DecidingPathStatus]: DECIDING->NOT_DECIDED. path has collision with objects"); return {DecidingPathStatus::NOT_DECIDED, clock_->now()}; } + if (enable_safety_check && !isSafePath().first) { + RCLCPP_DEBUG( + getLogger(), + "[DecidingPathStatus]: DECIDING->NOT_DECIDED. path is not safe against dynamic objects"); + return {DecidingPathStatus::NOT_DECIDED, clock_->now()}; + } + // if enough time has passed since deciding status starts, transition to DECIDED constexpr double check_collision_duration = 1.0; const double elapsed_time_from_deciding = (clock_->now() - prev_status.second).seconds(); @@ -1406,7 +1419,7 @@ bool GoalPlannerModule::isStuck() parameters_->use_object_recognition && checkObjectsCollision( thread_safe_data_.get_pull_over_path()->getCurrentPath(), - parameters_->object_recognition_collision_check_margin)) { + /*extract_static_objects=*/false, parameters_->object_recognition_collision_check_margin)) { return true; } @@ -1519,16 +1532,24 @@ bool GoalPlannerModule::checkOccupancyGridCollision(const PathWithLaneId & path) bool GoalPlannerModule::checkObjectsCollision( const PathWithLaneId & path, const double collision_check_margin, - const bool update_debug_data) const -{ - const auto pull_over_lane_stop_objects = - goal_planner_utils::extractStaticObjectsInExpandedPullOverLanes( - *(planner_data_->route_handler), left_side_parking_, parameters_->backward_goal_search_length, - parameters_->forward_goal_search_length, parameters_->detection_bound_offset, - *(planner_data_->dynamic_object), parameters_->th_moving_object_velocity); + const bool extract_static_objects, const bool update_debug_data) const +{ + const auto target_objects = std::invoke([&]() { + const auto & p = parameters_; + const auto & rh = *(planner_data_->route_handler); + const auto objects = *(planner_data_->dynamic_object); + if (extract_static_objects) { + return goal_planner_utils::extractStaticObjectsInExpandedPullOverLanes( + rh, left_side_parking_, p->backward_goal_search_length, p->forward_goal_search_length, + p->detection_bound_offset, objects, p->th_moving_object_velocity); + } + return goal_planner_utils::extractObjectsInExpandedPullOverLanes( + rh, left_side_parking_, p->backward_goal_search_length, p->forward_goal_search_length, + p->detection_bound_offset, objects); + }); std::vector obj_polygons; - for (const auto & object : pull_over_lane_stop_objects.objects) { + for (const auto & object : target_objects.objects) { obj_polygons.push_back(tier4_autoware_utils::toPolygon2d(object)); } From 02ba67fee4785dfcbda382c3315764464ba9b90e Mon Sep 17 00:00:00 2001 From: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Date: Sat, 27 Jan 2024 14:12:43 +0900 Subject: [PATCH 025/132] fix(avoidance): turn signal doesn't turn on (#6188) Signed-off-by: satoshi-ota --- planning/behavior_path_avoidance_module/src/utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/planning/behavior_path_avoidance_module/src/utils.cpp b/planning/behavior_path_avoidance_module/src/utils.cpp index 3a9b5db283304..953f3f5cb2f2f 100644 --- a/planning/behavior_path_avoidance_module/src/utils.cpp +++ b/planning/behavior_path_avoidance_module/src/utils.cpp @@ -2278,11 +2278,11 @@ TurnSignalInfo calcTurnSignalInfo( return {}; } - const auto left_lanelets = rh->getAllLeftSharedLinestringLanelets(lanelet, true, true); - const auto right_lanelets = rh->getAllRightSharedLinestringLanelets(lanelet, true, true); + const auto left_lane = rh->getLeftLanelet(lanelet, true, true); + const auto right_lane = rh->getRightLanelet(lanelet, true, true); if (!existShiftSideLane( - start_shift_length, end_shift_length, left_lanelets.empty(), right_lanelets.empty())) { + start_shift_length, end_shift_length, !left_lane.has_value(), !right_lane.has_value())) { return {}; } From 1c4c3e3e5b41341c513b536da19efc297dba4dac Mon Sep 17 00:00:00 2001 From: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Date: Sun, 28 Jan 2024 14:00:19 +0900 Subject: [PATCH 026/132] feat(metrics_visualize_panel): add new plugin to show planning metrics (#6154) * feat(metrix_visualize_panel): add new plugin to show planning metrix Signed-off-by: satoshi-ota * fix(tier4_metrics_rviz_plugin): fix small issues Signed-off-by: satoshi-ota * chore: add maintainer Signed-off-by: satoshi-ota * docs(tier4_metrics_rviz_plugin): fix docs Signed-off-by: satoshi-ota --------- Signed-off-by: satoshi-ota --- .../tier4_metrics_rviz_plugin/CMakeLists.txt | 31 +++ evaluator/tier4_metrics_rviz_plugin/README.md | 16 ++ .../icons/classes/MetricsVisualizePanel.png | Bin 0 -> 18815 bytes .../tier4_metrics_rviz_plugin/package.xml | 30 +++ .../plugins/plugin_description.xml | 5 + .../src/metrics_visualize_panel.cpp | 86 ++++++++ .../src/metrics_visualize_panel.hpp | 205 ++++++++++++++++++ 7 files changed, 373 insertions(+) create mode 100644 evaluator/tier4_metrics_rviz_plugin/CMakeLists.txt create mode 100644 evaluator/tier4_metrics_rviz_plugin/README.md create mode 100644 evaluator/tier4_metrics_rviz_plugin/icons/classes/MetricsVisualizePanel.png create mode 100644 evaluator/tier4_metrics_rviz_plugin/package.xml create mode 100644 evaluator/tier4_metrics_rviz_plugin/plugins/plugin_description.xml create mode 100644 evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.cpp create mode 100644 evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.hpp diff --git a/evaluator/tier4_metrics_rviz_plugin/CMakeLists.txt b/evaluator/tier4_metrics_rviz_plugin/CMakeLists.txt new file mode 100644 index 0000000000000..4c1e8cf58c262 --- /dev/null +++ b/evaluator/tier4_metrics_rviz_plugin/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.14) +project(tier4_metrics_rviz_plugin) + +find_package(autoware_cmake REQUIRED) +autoware_package() + +find_package(Qt5 REQUIRED Core Widgets Charts) +set(QT_WIDGETS_LIB Qt5::Widgets) +set(QT_CHARTS_LIB Qt5::Charts) +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +add_definitions(-DQT_NO_KEYWORDS) + +ament_auto_add_library(${PROJECT_NAME} SHARED + src/metrics_visualize_panel.cpp +) + +target_link_libraries(${PROJECT_NAME} + ${QT_WIDGETS_LIB} + ${QT_CHARTS_LIB} +) + +target_compile_options(${PROJECT_NAME} PUBLIC -Wno-error=deprecated-copy -Wno-error=pedantic) +# Export the plugin to be imported by rviz2 +pluginlib_export_plugin_description_file(rviz_common plugins/plugin_description.xml) + +ament_auto_package( + INSTALL_TO_SHARE + icons + plugins +) diff --git a/evaluator/tier4_metrics_rviz_plugin/README.md b/evaluator/tier4_metrics_rviz_plugin/README.md new file mode 100644 index 0000000000000..be94141254030 --- /dev/null +++ b/evaluator/tier4_metrics_rviz_plugin/README.md @@ -0,0 +1,16 @@ +# tier4_metrics_rviz_plugin + +## Purpose + +This plugin panel to visualize `planning_evaluator` output. + +## Inputs / Outputs + +| Name | Type | Description | +| ---------------------------------------- | --------------------------------------- | ------------------------------------- | +| `/diagnostic/planning_evaluator/metrics` | `diagnostic_msgs::msg::DiagnosticArray` | Subscribe `planning_evaluator` output | + +## HowToUse + +1. Start rviz and select panels/Add new panel. +2. Select MetricsVisualizePanel and press OK. diff --git a/evaluator/tier4_metrics_rviz_plugin/icons/classes/MetricsVisualizePanel.png b/evaluator/tier4_metrics_rviz_plugin/icons/classes/MetricsVisualizePanel.png new file mode 100644 index 0000000000000000000000000000000000000000..6a67573717ae18b6008e00077defb27256415663 GIT binary patch literal 18815 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 QxT*u><#`b=z=h}h2b9~@i2wiq literal 0 HcmV?d00001 diff --git a/evaluator/tier4_metrics_rviz_plugin/package.xml b/evaluator/tier4_metrics_rviz_plugin/package.xml new file mode 100644 index 0000000000000..7bd930f4f3c4c --- /dev/null +++ b/evaluator/tier4_metrics_rviz_plugin/package.xml @@ -0,0 +1,30 @@ + + + + tier4_metrics_rviz_plugin + 0.0.0 + The tier4_metrics_rviz_plugin package + Satoshi OTA + Kyoichi Sugahara + Maxime CLEMENT + Apache License 2.0 + + ament_cmake_auto + autoware_cmake + + diagnostic_msgs + libqt5-core + libqt5-gui + libqt5-widgets + qtbase5-dev + rclcpp + rviz_common + + ament_lint_auto + autoware_lint_common + + + ament_cmake + + + diff --git a/evaluator/tier4_metrics_rviz_plugin/plugins/plugin_description.xml b/evaluator/tier4_metrics_rviz_plugin/plugins/plugin_description.xml new file mode 100644 index 0000000000000..5aca5bd7faa54 --- /dev/null +++ b/evaluator/tier4_metrics_rviz_plugin/plugins/plugin_description.xml @@ -0,0 +1,5 @@ + + + MetricsVisualizePanel + + diff --git a/evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.cpp b/evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.cpp new file mode 100644 index 0000000000000..79da02b9b65c6 --- /dev/null +++ b/evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.cpp @@ -0,0 +1,86 @@ +// Copyright 2024 TIER IV, Inc. All rights reserved. +// +// 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 "metrics_visualize_panel.hpp" + +#include + +#include + +#include +#include +#include +#include + +namespace rviz_plugins +{ +MetricsVisualizePanel::MetricsVisualizePanel(QWidget * parent) +: rviz_common::Panel(parent), grid_(new QGridLayout()) +{ + setLayout(grid_); +} + +void MetricsVisualizePanel::onInitialize() +{ + using std::placeholders::_1; + + raw_node_ = this->getDisplayContext()->getRosNodeAbstraction().lock()->get_raw_node(); + + sub_ = raw_node_->create_subscription( + "/diagnostic/planning_evaluator/metrics", rclcpp::QoS{1}, + std::bind(&MetricsVisualizePanel::onMetrics, this, _1)); + + const auto period = std::chrono::milliseconds(static_cast(1e3 / 10)); + timer_ = raw_node_->create_wall_timer(period, [&]() { onTimer(); }); +} + +void MetricsVisualizePanel::onTimer() +{ + std::lock_guard message_lock(mutex_); + + for (auto & [name, metric] : metrics_) { + metric.updateGraph(); + metric.updateTable(); + } +} + +void MetricsVisualizePanel::onMetrics(const DiagnosticArray::ConstSharedPtr msg) +{ + std::lock_guard message_lock(mutex_); + + const auto time = msg->header.stamp.sec + msg->header.stamp.nanosec * 1e-9; + + constexpr size_t GRAPH_COL_SIZE = 5; + for (size_t i = 0; i < msg->status.size(); ++i) { + const auto & status = msg->status.at(i); + + if (metrics_.count(status.name) == 0) { + auto metric = Metric(status); + metrics_.emplace(status.name, metric); + grid_->addWidget(metric.getTable(), i / GRAPH_COL_SIZE * 2, i % GRAPH_COL_SIZE); + grid_->setRowStretch(i / GRAPH_COL_SIZE * 2, false); + grid_->addWidget(metric.getChartView(), i / GRAPH_COL_SIZE * 2 + 1, i % GRAPH_COL_SIZE); + grid_->setRowStretch(i / GRAPH_COL_SIZE * 2 + 1, true); + grid_->setColumnStretch(i % GRAPH_COL_SIZE, true); + } + + metrics_.at(status.name).updateData(time, status); + } +} + +} // namespace rviz_plugins + +#include +PLUGINLIB_EXPORT_CLASS(rviz_plugins::MetricsVisualizePanel, rviz_common::Panel) diff --git a/evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.hpp b/evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.hpp new file mode 100644 index 0000000000000..6708ecd7071e9 --- /dev/null +++ b/evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.hpp @@ -0,0 +1,205 @@ +// Copyright 2024 TIER IV, Inc. All rights reserved. +// +// 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 METRICS_VISUALIZE_PANEL_HPP_ +#define METRICS_VISUALIZE_PANEL_HPP_ + +#ifndef Q_MOC_RUN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + +#include + +#include +#include +#include + +namespace rviz_plugins +{ + +using diagnostic_msgs::msg::DiagnosticArray; +using diagnostic_msgs::msg::DiagnosticStatus; +using diagnostic_msgs::msg::KeyValue; +using QtCharts::QChart; +using QtCharts::QChartView; +using QtCharts::QLineSeries; + +struct Metric +{ +public: + explicit Metric(const DiagnosticStatus & status) : chart(new QChartView), table(new QTableWidget) + { + init(status); + } + + void init(const DiagnosticStatus & status) + { + QStringList header{}; + + { + auto label = new QLabel; + label->setAlignment(Qt::AlignCenter); + label->setText("metric_name"); + labels.emplace("metric_name", label); + + header.push_back(QString::fromStdString(status.name)); + } + + for (const auto & [key, value] : status.values) { + auto label = new QLabel; + label->setAlignment(Qt::AlignCenter); + labels.emplace(key, label); + + auto plot = new QLineSeries; + plot->setName(QString::fromStdString(key)); + plots.emplace(key, plot); + chart->chart()->addSeries(plot); + chart->chart()->createDefaultAxes(); + + header.push_back(QString::fromStdString(key)); + } + + { + chart->chart()->setTitle(QString::fromStdString(status.name)); + chart->chart()->legend()->setVisible(true); + chart->chart()->legend()->detachFromChart(); + chart->setRenderHint(QPainter::Antialiasing); + } + + { + table->setColumnCount(status.values.size() + 1); + table->setHorizontalHeaderLabels(header); + table->verticalHeader()->hide(); + table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + table->setRowCount(1); + table->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + } + } + + void updateData(const double time, const DiagnosticStatus & status) + { + for (const auto & [key, value] : status.values) { + const double data = std::stod(value); + labels.at(key)->setText(QString::fromStdString(toString(data))); + plots.at(key)->append(time, data); + updateMinMax(data); + } + + { + const auto area = chart->chart()->plotArea(); + const auto rect = chart->chart()->legend()->rect(); + chart->chart()->legend()->setGeometry( + QRectF(area.x(), area.y(), area.width(), rect.height())); + chart->chart()->axes(Qt::Horizontal).front()->setRange(time - 100.0, time); + } + + { + table->setCellWidget(0, 0, labels.at("metric_name")); + } + + for (size_t i = 0; i < status.values.size(); ++i) { + table->setCellWidget(0, i + 1, labels.at(status.values.at(i).key)); + } + } + + void updateMinMax(double data) + { + if (data < y_range_min) { + y_range_min = data > 0.0 ? 0.9 * data : 1.1 * data; + chart->chart()->axes(Qt::Vertical).front()->setMin(y_range_min); + } + + if (data > y_range_max) { + y_range_max = data > 0.0 ? 1.1 * data : 0.9 * data; + chart->chart()->axes(Qt::Vertical).front()->setMax(y_range_max); + } + } + + void updateTable() { table->update(); } + + void updateGraph() { chart->update(); } + + QChartView * getChartView() const { return chart; } + + QTableWidget * getTable() const { return table; } + +private: + static std::optional getValue(const DiagnosticStatus & status, std::string && key) + { + const auto itr = std::find_if( + status.values.begin(), status.values.end(), + [&](const auto & value) { return value.key == key; }); + + if (itr == status.values.end()) { + return std::nullopt; + } + + return itr->value; + } + + static std::string toString(const double & value) + { + std::stringstream ss; + ss << std::scientific << std::setprecision(2) << value; + return ss.str(); + } + + QChartView * chart; + QTableWidget * table; + + std::unordered_map labels; + std::unordered_map plots; + + double y_range_min{std::numeric_limits::max()}; + double y_range_max{std::numeric_limits::lowest()}; +}; + +class MetricsVisualizePanel : public rviz_common::Panel +{ + Q_OBJECT + +public: + explicit MetricsVisualizePanel(QWidget * parent = nullptr); + void onInitialize() override; + +private Q_SLOTS: + +private: + rclcpp::Node::SharedPtr raw_node_; + rclcpp::TimerBase::SharedPtr timer_; + rclcpp::Subscription::SharedPtr sub_; + + void onTimer(); + void onMetrics(const DiagnosticArray::ConstSharedPtr msg); + + QGridLayout * grid_; + + std::mutex mutex_; + std::unordered_map metrics_; +}; +} // namespace rviz_plugins + +#endif // METRICS_VISUALIZE_PANEL_HPP_ From 6835bc47da0f596079514454e220375f2b9030d5 Mon Sep 17 00:00:00 2001 From: Kotaro Uetake <60615504+ktro2828@users.noreply.github.com> Date: Mon, 29 Jan 2024 09:02:15 +0900 Subject: [PATCH 027/132] refactor: update TRT build log (#6117) * feat: add support of throttle logging Signed-off-by: ktro2828 * refactor: replace custom `Logger` to `tensorrt_common::Logger` Signed-off-by: ktro2828 * refactor: update to display standard output on screen Signed-off-by: ktro2828 * refactor: update log message while building engine from onnx Signed-off-by: ktro2828 * refactor: update logger in `lidar_centerpoint` Signed-off-by: ktro2828 * refactor: update log message Signed-off-by: ktro2828 * refactor: set default verbose=true for bulding engine from onnx Signed-off-by: ktro2828 * refactor: remove including unused `rclcpp.hpp` Signed-off-by: ktro2828 * refactor: update launcher to output logs on screen Signed-off-by: ktro2828 --------- Signed-off-by: ktro2828 Co-authored-by: Shunsuke Miura <37187849+miursh@users.noreply.github.com> --- .../include/tensorrt_common/logger.hpp | 63 ++++++++++++++++--- .../tensorrt_common/src/tensorrt_common.cpp | 4 ++ .../lib/network/network_trt.cpp | 7 +-- .../lib/network/tensorrt_wrapper.cpp | 40 ++++++------ .../tensorrt_yolo/lib/include/trt_yolo.hpp | 20 +----- perception/tensorrt_yolo/lib/src/trt_yolo.cpp | 35 ++++++----- perception/tensorrt_yolo/package.xml | 1 + .../traffic_light_classifier.launch.xml | 2 +- .../traffic_light_fine_detector.launch.xml | 2 +- ...traffic_light_ssd_fine_detector.launch.xml | 2 +- .../lib/include/trt_ssd.hpp | 21 ++----- .../lib/src/trt_ssd.cpp | 35 ++++++----- .../package.xml | 1 + 13 files changed, 133 insertions(+), 100 deletions(-) diff --git a/common/tensorrt_common/include/tensorrt_common/logger.hpp b/common/tensorrt_common/include/tensorrt_common/logger.hpp index 98fe18794998d..73190d13b9de3 100644 --- a/common/tensorrt_common/include/tensorrt_common/logger.hpp +++ b/common/tensorrt_common/include/tensorrt_common/logger.hpp @@ -19,6 +19,7 @@ #include "NvInferRuntimeCommon.h" +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include namespace tensorrt_common { @@ -200,7 +202,15 @@ class Logger : public nvinfer1::ILogger // NOLINT public: // Logger(Severity severity = Severity::kWARNING) // Logger(Severity severity = Severity::kVERBOSE) - explicit Logger(Severity severity = Severity::kINFO) : mReportableSeverity(severity) {} + explicit Logger(Severity severity = Severity::kINFO) + : mReportableSeverity(severity), mVerbose(true), mThrottleStopFlag(false) + { + } + + explicit Logger(const bool verbose, Severity severity = Severity::kINFO) + : mReportableSeverity(severity), mVerbose(verbose), mThrottleStopFlag(false) + { + } //! //! \enum TestResult @@ -234,7 +244,44 @@ class Logger : public nvinfer1::ILogger // NOLINT //! void log(Severity severity, const char * msg) noexcept override { - LogStreamConsumer(mReportableSeverity, severity) << "[TRT] " << std::string(msg) << std::endl; + if (mVerbose) { + LogStreamConsumer(mReportableSeverity, severity) << "[TRT] " << std::string(msg) << std::endl; + } + } + + /** + * @brief Logging with throttle. + * + * @example + * Logger logger(); + * auto log_thread = logger.log_throttle(nvinfer1::ILogger::Severity::kINFO, "SOME MSG", 1); + * // some operation + * logger.stop_throttle(log_thread); + * + * @param severity + * @param msg + * @param duration + * @return std::thread + * + */ + std::thread log_throttle(Severity severity, const char * msg, const int duration) noexcept + { + mThrottleStopFlag.store(false); + auto log_func = [this](Severity s, const char * m, const int d) { + while (!mThrottleStopFlag.load()) { + this->log(s, m); + std::this_thread::sleep_for(std::chrono::seconds(d)); + } + }; + + std::thread log_thread(log_func, severity, msg, duration); + return log_thread; + } + + void stop_throttle(std::thread & log_thread) noexcept + { + mThrottleStopFlag.store(true); + log_thread.join(); } //! @@ -430,6 +477,8 @@ class Logger : public nvinfer1::ILogger // NOLINT } Severity mReportableSeverity; + bool mVerbose; + std::atomic mThrottleStopFlag; }; namespace @@ -444,7 +493,7 @@ namespace //! inline LogStreamConsumer LOG_VERBOSE(const Logger & logger) { - return LogStreamConsumer(logger.getReportableSeverity(), Severity::kVERBOSE); + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kVERBOSE) << "[TRT] "; } //! @@ -456,7 +505,7 @@ inline LogStreamConsumer LOG_VERBOSE(const Logger & logger) //! inline LogStreamConsumer LOG_INFO(const Logger & logger) { - return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINFO); + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINFO) << "[TRT] "; } //! @@ -468,7 +517,7 @@ inline LogStreamConsumer LOG_INFO(const Logger & logger) //! inline LogStreamConsumer LOG_WARN(const Logger & logger) { - return LogStreamConsumer(logger.getReportableSeverity(), Severity::kWARNING); + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kWARNING) << "[TRT] "; } //! @@ -480,7 +529,7 @@ inline LogStreamConsumer LOG_WARN(const Logger & logger) //! inline LogStreamConsumer LOG_ERROR(const Logger & logger) { - return LogStreamConsumer(logger.getReportableSeverity(), Severity::kERROR); + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kERROR) << "[TRT] "; } //! @@ -494,7 +543,7 @@ inline LogStreamConsumer LOG_ERROR(const Logger & logger) //! inline LogStreamConsumer LOG_FATAL(const Logger & logger) { - return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINTERNAL_ERROR); + return LogStreamConsumer(logger.getReportableSeverity(), Severity::kINTERNAL_ERROR) << "[TRT] "; } } // anonymous namespace diff --git a/common/tensorrt_common/src/tensorrt_common.cpp b/common/tensorrt_common/src/tensorrt_common.cpp index f1e4835d2ba2d..2b218cd3e49f2 100644 --- a/common/tensorrt_common/src/tensorrt_common.cpp +++ b/common/tensorrt_common/src/tensorrt_common.cpp @@ -186,7 +186,11 @@ void TrtCommon::setup() } else { std::cout << "Building... " << cache_engine_path << std::endl; logger_.log(nvinfer1::ILogger::Severity::kINFO, "Start build engine"); + auto log_thread = logger_.log_throttle( + nvinfer1::ILogger::Severity::kINFO, + "Applying optimizations and building TRT CUDA engine. Please wait for a few minutes...", 5); buildEngineFromOnnx(model_file_path_, cache_engine_path); + logger_.stop_throttle(log_thread); logger_.log(nvinfer1::ILogger::Severity::kINFO, "End build engine"); } engine_path = cache_engine_path; diff --git a/perception/lidar_centerpoint/lib/network/network_trt.cpp b/perception/lidar_centerpoint/lib/network/network_trt.cpp index 2d841d22c2eb1..ad1a7ae90630c 100644 --- a/perception/lidar_centerpoint/lib/network/network_trt.cpp +++ b/perception/lidar_centerpoint/lib/network/network_trt.cpp @@ -14,8 +14,6 @@ #include "lidar_centerpoint/network/network_trt.hpp" -#include - namespace centerpoint { bool VoxelEncoderTRT::setProfile( @@ -65,9 +63,8 @@ bool HeadTRT::setProfile( if ( out_name == std::string("heatmap") && network.getOutput(ci)->getDimensions().d[1] != static_cast(out_channel_sizes_[ci])) { - RCLCPP_ERROR( - rclcpp::get_logger("lidar_centerpoint"), - "Expected and actual number of classes do not match"); + tensorrt_common::LOG_ERROR(logger_) + << "Expected and actual number of classes do not match" << std::endl; return false; } auto out_dims = nvinfer1::Dims4( diff --git a/perception/lidar_centerpoint/lib/network/tensorrt_wrapper.cpp b/perception/lidar_centerpoint/lib/network/tensorrt_wrapper.cpp index 2255df99dbcf4..91fcce9a80f78 100644 --- a/perception/lidar_centerpoint/lib/network/tensorrt_wrapper.cpp +++ b/perception/lidar_centerpoint/lib/network/tensorrt_wrapper.cpp @@ -14,8 +14,6 @@ #include "lidar_centerpoint/network/tensorrt_wrapper.hpp" -#include - #include #include @@ -42,7 +40,7 @@ bool TensorRTWrapper::init( runtime_ = tensorrt_common::TrtUniquePtr(nvinfer1::createInferRuntime(logger_)); if (!runtime_) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to create runtime"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to create runtime" << std::endl; return false; } @@ -51,7 +49,11 @@ bool TensorRTWrapper::init( if (engine_file.is_open()) { success = loadEngine(engine_path); } else { + auto log_thread = logger_.log_throttle( + nvinfer1::ILogger::Severity::kINFO, + "Applying optimizations and building TRT CUDA engine. Please wait a minutes...", 5); success = parseONNX(onnx_path, engine_path, precision); + logger_.stop_throttle(log_thread); } success &= createContext(); @@ -61,15 +63,15 @@ bool TensorRTWrapper::init( bool TensorRTWrapper::createContext() { if (!engine_) { - RCLCPP_ERROR( - rclcpp::get_logger("lidar_centerpoint"), "Failed to create context: Engine was not created"); + tensorrt_common::LOG_ERROR(logger_) + << "Failed to create context: Engine was not created" << std::endl; return false; } context_ = tensorrt_common::TrtUniquePtr(engine_->createExecutionContext()); if (!context_) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to create context"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to create context" << std::endl; return false; } @@ -83,14 +85,14 @@ bool TensorRTWrapper::parseONNX( auto builder = tensorrt_common::TrtUniquePtr(nvinfer1::createInferBuilder(logger_)); if (!builder) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to create builder"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to create builder" << std::endl; return false; } auto config = tensorrt_common::TrtUniquePtr(builder->createBuilderConfig()); if (!config) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to create config"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to create config" << std::endl; return false; } #if (NV_TENSORRT_MAJOR * 1000) + (NV_TENSORRT_MINOR * 100) + NV_TENSOR_PATCH >= 8400 @@ -100,12 +102,11 @@ bool TensorRTWrapper::parseONNX( #endif if (precision == "fp16") { if (builder->platformHasFastFp16()) { - RCLCPP_INFO(rclcpp::get_logger("lidar_centerpoint"), "Using TensorRT FP16 Inference"); + tensorrt_common::LOG_INFO(logger_) << "Using TensorRT FP16 Inference" << std::endl; config->setFlag(nvinfer1::BuilderFlag::kFP16); } else { - RCLCPP_INFO( - rclcpp::get_logger("lidar_centerpoint"), - "TensorRT FP16 Inference isn't supported in this environment"); + tensorrt_common::LOG_INFO(logger_) + << "TensorRT FP16 Inference isn't supported in this environment" << std::endl; } } @@ -114,7 +115,7 @@ bool TensorRTWrapper::parseONNX( auto network = tensorrt_common::TrtUniquePtr(builder->createNetworkV2(flag)); if (!network) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to create network"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to create network" << std::endl; return false; } @@ -123,23 +124,20 @@ bool TensorRTWrapper::parseONNX( parser->parseFromFile(onnx_path.c_str(), static_cast(nvinfer1::ILogger::Severity::kERROR)); if (!setProfile(*builder, *network, *config)) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to set profile"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to set profile" << std::endl; return false; } - RCLCPP_INFO_STREAM( - rclcpp::get_logger("lidar_centerpoint"), - "Applying optimizations and building TRT CUDA engine (" << onnx_path << ") ..."); plan_ = tensorrt_common::TrtUniquePtr( builder->buildSerializedNetwork(*network, *config)); if (!plan_) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to create serialized network"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to create serialized network" << std::endl; return false; } engine_ = tensorrt_common::TrtUniquePtr( runtime_->deserializeCudaEngine(plan_->data(), plan_->size())); if (!engine_) { - RCLCPP_ERROR(rclcpp::get_logger("lidar_centerpoint"), "Failed to create engine"); + tensorrt_common::LOG_ERROR(logger_) << "Failed to create engine" << std::endl; return false; } @@ -148,7 +146,7 @@ bool TensorRTWrapper::parseONNX( bool TensorRTWrapper::saveEngine(const std::string & engine_path) { - RCLCPP_INFO_STREAM(rclcpp::get_logger("lidar_centerpoint"), "Writing to " << engine_path); + tensorrt_common::LOG_INFO(logger_) << "Writing to " << engine_path << std::endl; std::ofstream file(engine_path, std::ios::out | std::ios::binary); file.write(reinterpret_cast(plan_->data()), plan_->size()); return true; @@ -162,7 +160,7 @@ bool TensorRTWrapper::loadEngine(const std::string & engine_path) std::string engine_str = engine_buffer.str(); engine_ = tensorrt_common::TrtUniquePtr(runtime_->deserializeCudaEngine( reinterpret_cast(engine_str.data()), engine_str.size())); - RCLCPP_INFO_STREAM(rclcpp::get_logger("lidar_centerpoint"), "Loaded engine from " << engine_path); + tensorrt_common::LOG_INFO(logger_) << "Loaded engine from " << engine_path << std::endl; return true; } diff --git a/perception/tensorrt_yolo/lib/include/trt_yolo.hpp b/perception/tensorrt_yolo/lib/include/trt_yolo.hpp index af8065ffed379..a64c94c008526 100644 --- a/perception/tensorrt_yolo/lib/include/trt_yolo.hpp +++ b/perception/tensorrt_yolo/lib/include/trt_yolo.hpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -67,22 +68,6 @@ struct Deleter template using unique_ptr = std::unique_ptr; -class Logger : public nvinfer1::ILogger -{ -public: - explicit Logger(bool verbose) : verbose_(verbose) {} - - void log(Severity severity, const char * msg) noexcept override - { - if (verbose_ || ((severity != Severity::kINFO) && (severity != Severity::kVERBOSE))) { - std::cout << msg << std::endl; - } - } - -private: - bool verbose_{false}; -}; - struct Config { int num_anchors; @@ -105,7 +90,7 @@ class Net Net( const std::string & onnx_file_path, const std::string & precision, const int max_batch_size, const Config & yolo_config, const std::vector & calibration_images, - const std::string & calibration_table, bool verbose = false, + const std::string & calibration_table, bool verbose = true, size_t workspace_size = (1ULL << 30)); ~Net(); @@ -138,6 +123,7 @@ class Net cuda::unique_ptr out_scores_d_ = nullptr; cuda::unique_ptr out_boxes_d_ = nullptr; cuda::unique_ptr out_classes_d_ = nullptr; + tensorrt_common::Logger logger_; void load(const std::string & path); bool prepare(); diff --git a/perception/tensorrt_yolo/lib/src/trt_yolo.cpp b/perception/tensorrt_yolo/lib/src/trt_yolo.cpp index 7f1d2dbbf4577..c8793aa4c8512 100644 --- a/perception/tensorrt_yolo/lib/src/trt_yolo.cpp +++ b/perception/tensorrt_yolo/lib/src/trt_yolo.cpp @@ -113,10 +113,9 @@ std::vector Net::preprocess( return result; } -Net::Net(const std::string & path, bool verbose) +Net::Net(const std::string & path, bool verbose) : logger_(verbose) { - Logger logger(verbose); - runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger)); + runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger_)); load(path); if (!prepare()) { std::cout << "Fail to prepare engine" << std::endl; @@ -136,9 +135,9 @@ Net::Net( const std::string & onnx_file_path, const std::string & precision, const int max_batch_size, const Config & yolo_config, const std::vector & calibration_images, const std::string & calibration_table, bool verbose, size_t workspace_size) +: logger_(verbose) { - Logger logger(verbose); - runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger)); + runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger_)); if (!runtime_) { std::cout << "Fail to create runtime" << std::endl; return; @@ -147,7 +146,7 @@ Net::Net( bool int8 = precision.compare("INT8") == 0; // Create builder - auto builder = unique_ptr(nvinfer1::createInferBuilder(logger)); + auto builder = unique_ptr(nvinfer1::createInferBuilder(logger_)); if (!builder) { std::cout << "Fail to create builder" << std::endl; return; @@ -168,20 +167,23 @@ Net::Net( #endif // Parse ONNX FCN - std::cout << "Building " << precision << " core model..." << std::endl; + tensorrt_common::LOG_INFO(logger_) << "Building " << precision << " core model..." << std::endl; const auto flag = 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); auto network = unique_ptr(builder->createNetworkV2(flag)); if (!network) { - std::cout << "Fail to create network" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create network" << std::endl; return; } - auto parser = unique_ptr(nvonnxparser::createParser(*network, logger)); + auto parser = unique_ptr(nvonnxparser::createParser(*network, logger_)); if (!parser) { - std::cout << "Fail to create parser" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create parser" << std::endl; return; } + auto log_thread = logger_.log_throttle( + nvinfer1::ILogger::Severity::kINFO, + "Applying optimizations and building TRT CUDA engine. Please wait for a few minutes...", 5); parser->parseFromFile( onnx_file_path.c_str(), static_cast(nvinfer1::ILogger::Severity::kERROR)); std::vector scores, boxes, classes; @@ -250,28 +252,31 @@ Net::Net( calib = std::make_unique(stream, calibration_table); config->setInt8Calibrator(calib.get()); } else { - std::cout << "Fail to find enough images for INT8 calibration. Build FP mode..." << std::endl; + tensorrt_common::LOG_WARN(logger_) + << "Fail to find enough images for INT8 calibration. Build FP mode..." << std::endl; } } // Build engine - std::cout << "Applying optimizations and building TRT CUDA engine..." << std::endl; plan_ = unique_ptr(builder->buildSerializedNetwork(*network, *config)); if (!plan_) { - std::cout << "Fail to create serialized network" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create serialized network" << std::endl; + logger_.stop_throttle(log_thread); return; } engine_ = unique_ptr( runtime_->deserializeCudaEngine(plan_->data(), plan_->size())); if (!prepare()) { - std::cout << "Fail to create engine" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create engine" << std::endl; + logger_.stop_throttle(log_thread); return; } + logger_.stop_throttle(log_thread); } void Net::save(const std::string & path) const { - std::cout << "Writing to " << path << "..." << std::endl; + tensorrt_common::LOG_INFO(logger_) << "Writing to " << path << "..." << std::endl; std::ofstream file(path, std::ios::out | std::ios::binary); file.write(reinterpret_cast(plan_->data()), plan_->size()); } diff --git a/perception/tensorrt_yolo/package.xml b/perception/tensorrt_yolo/package.xml index 8a6756449b70f..12d07647093b5 100755 --- a/perception/tensorrt_yolo/package.xml +++ b/perception/tensorrt_yolo/package.xml @@ -16,6 +16,7 @@ rclcpp rclcpp_components sensor_msgs + tensorrt_common tier4_perception_msgs ament_lint_auto diff --git a/perception/traffic_light_classifier/launch/traffic_light_classifier.launch.xml b/perception/traffic_light_classifier/launch/traffic_light_classifier.launch.xml index 343531f4a00f1..e96f21b8ff01b 100644 --- a/perception/traffic_light_classifier/launch/traffic_light_classifier.launch.xml +++ b/perception/traffic_light_classifier/launch/traffic_light_classifier.launch.xml @@ -17,7 +17,7 @@ - + diff --git a/perception/traffic_light_fine_detector/launch/traffic_light_fine_detector.launch.xml b/perception/traffic_light_fine_detector/launch/traffic_light_fine_detector.launch.xml index 6e32d3410c260..e7a68ea9b9e94 100644 --- a/perception/traffic_light_fine_detector/launch/traffic_light_fine_detector.launch.xml +++ b/perception/traffic_light_fine_detector/launch/traffic_light_fine_detector.launch.xml @@ -12,7 +12,7 @@ - + diff --git a/perception/traffic_light_ssd_fine_detector/launch/traffic_light_ssd_fine_detector.launch.xml b/perception/traffic_light_ssd_fine_detector/launch/traffic_light_ssd_fine_detector.launch.xml index 714c4d288b603..ad2851ced39c6 100644 --- a/perception/traffic_light_ssd_fine_detector/launch/traffic_light_ssd_fine_detector.launch.xml +++ b/perception/traffic_light_ssd_fine_detector/launch/traffic_light_ssd_fine_detector.launch.xml @@ -16,7 +16,7 @@ - + diff --git a/perception/traffic_light_ssd_fine_detector/lib/include/trt_ssd.hpp b/perception/traffic_light_ssd_fine_detector/lib/include/trt_ssd.hpp index 52d411c253fe5..00c21cdcaf29e 100644 --- a/perception/traffic_light_ssd_fine_detector/lib/include/trt_ssd.hpp +++ b/perception/traffic_light_ssd_fine_detector/lib/include/trt_ssd.hpp @@ -15,6 +15,8 @@ #ifndef TRT_SSD_HPP_ #define TRT_SSD_HPP_ +#include + #include <./cuda_runtime.h> #include @@ -39,22 +41,6 @@ struct Deleter template using unique_ptr = std::unique_ptr; -class Logger : public nvinfer1::ILogger -{ -public: - explicit Logger(bool verbose) : verbose_(verbose) {} - - void log(Severity severity, const char * msg) noexcept override - { - if (verbose_ || ((severity != Severity::kINFO) && (severity != Severity::kVERBOSE))) { - std::cout << msg << std::endl; - } - } - -private: - bool verbose_{false}; -}; - struct Shape { int channel, width, height; @@ -78,7 +64,7 @@ class Net // Create engine from serialized onnx model Net( const std::string & onnx_file_path, const std::string & precision, const int max_batch_size, - bool verbose = false, size_t workspace_size = (1ULL << 30)); + bool verbose = true, size_t workspace_size = (1ULL << 30)); ~Net(); @@ -127,6 +113,7 @@ class Net unique_ptr engine_ = nullptr; unique_ptr context_ = nullptr; cudaStream_t stream_ = nullptr; + tensorrt_common::Logger logger_; void load(const std::string & path); void prepare(); diff --git a/perception/traffic_light_ssd_fine_detector/lib/src/trt_ssd.cpp b/perception/traffic_light_ssd_fine_detector/lib/src/trt_ssd.cpp index 22aa0f6bf3880..8aceb32d2ec58 100644 --- a/perception/traffic_light_ssd_fine_detector/lib/src/trt_ssd.cpp +++ b/perception/traffic_light_ssd_fine_detector/lib/src/trt_ssd.cpp @@ -52,10 +52,9 @@ void Net::prepare() cudaStreamCreate(&stream_); } -Net::Net(const std::string & path, bool verbose) +Net::Net(const std::string & path, bool verbose) : logger_(verbose) { - Logger logger(verbose); - runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger)); + runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger_)); load(path); prepare(); } @@ -70,9 +69,9 @@ Net::~Net() Net::Net( const std::string & onnx_file_path, const std::string & precision, const int max_batch_size, bool verbose, size_t workspace_size) +: logger_(verbose) { - Logger logger(verbose); - runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger)); + runtime_ = unique_ptr(nvinfer1::createInferRuntime(logger_)); if (!runtime_) { std::cout << "Fail to create runtime" << std::endl; return; @@ -81,7 +80,7 @@ Net::Net( bool int8 = precision.compare("INT8") == 0; // Create builder - auto builder = unique_ptr(nvinfer1::createInferBuilder(logger)); + auto builder = unique_ptr(nvinfer1::createInferBuilder(logger_)); if (!builder) { std::cout << "Fail to create builder" << std::endl; return; @@ -102,19 +101,22 @@ Net::Net( #endif // Parse ONNX FCN - std::cout << "Building " << precision << " core model..." << std::endl; + tensorrt_common::LOG_INFO(logger_) << "Building " << precision << " core model..." << std::endl; const auto flag = 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH); auto network = unique_ptr(builder->createNetworkV2(flag)); if (!network) { - std::cout << "Fail to create network" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create network" << std::endl; return; } - auto parser = unique_ptr(nvonnxparser::createParser(*network, logger)); + auto parser = unique_ptr(nvonnxparser::createParser(*network, logger_)); if (!parser) { - std::cout << "Fail to create parser" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create parser" << std::endl; return; } + auto log_thread = logger_.log_throttle( + nvinfer1::ILogger::Severity::kINFO, + "Applying optimizations and building TRT CUDA engine. Please wait for a few minutes...", 5); parser->parseFromFile( onnx_file_path.c_str(), static_cast(nvinfer1::ILogger::Severity::kERROR)); @@ -141,28 +143,31 @@ Net::Net( config->addOptimizationProfile(profile); // Build engine - std::cout << "Applying optimizations and building TRT CUDA engine..." << std::endl; plan_ = unique_ptr(builder->buildSerializedNetwork(*network, *config)); if (!plan_) { - std::cout << "Fail to create serialized network" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create serialized network" << std::endl; + logger_.stop_throttle(log_thread); return; } engine_ = unique_ptr( runtime_->deserializeCudaEngine(plan_->data(), plan_->size())); if (!engine_) { - std::cout << "Fail to create engine" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create engine" << std::endl; + logger_.stop_throttle(log_thread); return; } context_ = unique_ptr(engine_->createExecutionContext()); if (!context_) { - std::cout << "Fail to create context" << std::endl; + tensorrt_common::LOG_ERROR(logger_) << "Fail to create context" << std::endl; + logger_.stop_throttle(log_thread); return; } + logger_.stop_throttle(log_thread); } void Net::save(const std::string & path) { - std::cout << "Writing to " << path << "..." << std::endl; + tensorrt_common::LOG_INFO(logger_) << "Writing to " << path << "..." << std::endl; std::ofstream file(path, std::ios::out | std::ios::binary); file.write(reinterpret_cast(plan_->data()), plan_->size()); } diff --git a/perception/traffic_light_ssd_fine_detector/package.xml b/perception/traffic_light_ssd_fine_detector/package.xml index 994f84bacdae4..cd44857e8fe86 100644 --- a/perception/traffic_light_ssd_fine_detector/package.xml +++ b/perception/traffic_light_ssd_fine_detector/package.xml @@ -16,6 +16,7 @@ rclcpp rclcpp_components sensor_msgs + tensorrt_common tier4_debug_msgs tier4_perception_msgs From 521858470452ddeb0a61995fec58320fb88f5359 Mon Sep 17 00:00:00 2001 From: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Date: Mon, 29 Jan 2024 09:11:30 +0900 Subject: [PATCH 028/132] fix(avoidance): fix bug in turn signal decision (#6193) Signed-off-by: satoshi-ota --- .../behavior_path_avoidance_module/src/utils.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/planning/behavior_path_avoidance_module/src/utils.cpp b/planning/behavior_path_avoidance_module/src/utils.cpp index 953f3f5cb2f2f..5fe47715bff08 100644 --- a/planning/behavior_path_avoidance_module/src/utils.cpp +++ b/planning/behavior_path_avoidance_module/src/utils.cpp @@ -2278,11 +2278,15 @@ TurnSignalInfo calcTurnSignalInfo( return {}; } - const auto left_lane = rh->getLeftLanelet(lanelet, true, true); - const auto right_lane = rh->getRightLanelet(lanelet, true, true); - - if (!existShiftSideLane( - start_shift_length, end_shift_length, !left_lane.has_value(), !right_lane.has_value())) { + const auto left_same_direction_lane = rh->getLeftLanelet(lanelet, true, true); + const auto left_opposite_lanes = rh->getLeftOppositeLanelets(lanelet); + const auto right_same_direction_lane = rh->getRightLanelet(lanelet, true, true); + const auto right_opposite_lanes = rh->getRightOppositeLanelets(lanelet); + const auto has_left_lane = left_same_direction_lane.has_value() || !left_opposite_lanes.empty(); + const auto has_right_lane = + right_same_direction_lane.has_value() || !right_opposite_lanes.empty(); + + if (!existShiftSideLane(start_shift_length, end_shift_length, !has_left_lane, !has_right_lane)) { return {}; } From db637bb8f3b33b60e1d2d9648e0d563fbd149dcf Mon Sep 17 00:00:00 2001 From: kminoda <44218668+kminoda@users.noreply.github.com> Date: Mon, 29 Jan 2024 09:28:25 +0900 Subject: [PATCH 029/132] chore(detected_object_validation): rework parameters (#6166) chore(detected_object_validation): use config Signed-off-by: kminoda --- .../config/obstacle_pointcloud_based_validator.param.yaml | 1 + .../config/occupancy_grid_based_validator.param.yaml | 3 +++ .../launch/obstacle_pointcloud_based_validator.launch.xml | 1 - .../launch/occupancy_grid_based_validator.launch.xml | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 perception/detected_object_validation/config/occupancy_grid_based_validator.param.yaml diff --git a/perception/detected_object_validation/config/obstacle_pointcloud_based_validator.param.yaml b/perception/detected_object_validation/config/obstacle_pointcloud_based_validator.param.yaml index f7a27a52bfa8a..cddee782e8af0 100644 --- a/perception/detected_object_validation/config/obstacle_pointcloud_based_validator.param.yaml +++ b/perception/detected_object_validation/config/obstacle_pointcloud_based_validator.param.yaml @@ -13,3 +13,4 @@ [800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0] using_2d_validator: false + enable_debugger: false diff --git a/perception/detected_object_validation/config/occupancy_grid_based_validator.param.yaml b/perception/detected_object_validation/config/occupancy_grid_based_validator.param.yaml new file mode 100644 index 0000000000000..fc5c634735e23 --- /dev/null +++ b/perception/detected_object_validation/config/occupancy_grid_based_validator.param.yaml @@ -0,0 +1,3 @@ +/**: + ros__parameters: + enable_debug: false diff --git a/perception/detected_object_validation/launch/obstacle_pointcloud_based_validator.launch.xml b/perception/detected_object_validation/launch/obstacle_pointcloud_based_validator.launch.xml index 799b605658345..a1d941e66db4b 100644 --- a/perception/detected_object_validation/launch/obstacle_pointcloud_based_validator.launch.xml +++ b/perception/detected_object_validation/launch/obstacle_pointcloud_based_validator.launch.xml @@ -9,7 +9,6 @@ - diff --git a/perception/detected_object_validation/launch/occupancy_grid_based_validator.launch.xml b/perception/detected_object_validation/launch/occupancy_grid_based_validator.launch.xml index 04bcbd87172b3..3acb1f2d1907a 100644 --- a/perception/detected_object_validation/launch/occupancy_grid_based_validator.launch.xml +++ b/perception/detected_object_validation/launch/occupancy_grid_based_validator.launch.xml @@ -7,6 +7,7 @@ + @@ -22,6 +23,6 @@ - + From 6d6a7b06d8de8785a49937e45b778034d3501c8c Mon Sep 17 00:00:00 2001 From: Satoshi OTA <44889564+satoshi-ota@users.noreply.github.com> Date: Mon, 29 Jan 2024 09:28:49 +0900 Subject: [PATCH 030/132] feat(avoidance): make it possible to use freespace areas in avoidance module (#6001) * fix(static_drivable_area_expansion): check right/left bound id Signed-off-by: satoshi-ota * feat(static_drivable_area): use freespace area Signed-off-by: satoshi-ota * feat(avoidance): use freespace Signed-off-by: satoshi-ota * fix(AbLC): fix flag Signed-off-by: satoshi-ota * fix(planner_manager): fix flag Signed-off-by: satoshi-ota * refactor(static_drivable_area_expansion): remove unused arg Signed-off-by: satoshi-ota * refactor(static_drivable_area_expansion): use lambda Signed-off-by: satoshi-ota * fix(static_drivable_area_expansion): fix invalid access Signed-off-by: satoshi-ota * refactor(static_drivable_area_expansion): improve readability Signed-off-by: satoshi-ota * fix(avoidance): add param Signed-off-by: satoshi-ota --------- Signed-off-by: satoshi-ota --- .../src/scene.cpp | 6 +- .../config/avoidance.param.yaml | 1 + .../data_structs.hpp | 3 + .../parameter_helper.hpp | 1 + .../src/scene.cpp | 12 +- .../src/planner_manager.cpp | 5 +- .../data_manager.hpp | 1 + .../static_drivable_area.hpp | 28 +- .../static_drivable_area.cpp | 573 ++++++++++++------ 9 files changed, 417 insertions(+), 213 deletions(-) diff --git a/planning/behavior_path_avoidance_by_lane_change_module/src/scene.cpp b/planning/behavior_path_avoidance_by_lane_change_module/src/scene.cpp index 6107314bc2824..32c92b4f4b88b 100644 --- a/planning/behavior_path_avoidance_by_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_avoidance_by_lane_change_module/src/scene.cpp @@ -173,11 +173,9 @@ AvoidancePlanningData AvoidanceByLaneChange::calcAvoidancePlanningData( const auto shorten_lanes = utils::cutOverlappedLanes(data.reference_path_rough, data.drivable_lanes); data.left_bound = toLineString3d(utils::calcBound( - planner_data_->route_handler, shorten_lanes, avoidance_parameters_->use_hatched_road_markings, - avoidance_parameters_->use_intersection_areas, true)); + data.reference_path_rough, planner_data_, shorten_lanes, false, false, false, true)); data.right_bound = toLineString3d(utils::calcBound( - planner_data_->route_handler, shorten_lanes, avoidance_parameters_->use_hatched_road_markings, - avoidance_parameters_->use_intersection_areas, false)); + data.reference_path_rough, planner_data_, shorten_lanes, false, false, false, false)); // get related objects from dynamic_objects, and then separates them as target objects and non // target objects diff --git a/planning/behavior_path_avoidance_module/config/avoidance.param.yaml b/planning/behavior_path_avoidance_module/config/avoidance.param.yaml index b300de2236fcf..d9ae9ed623cb3 100644 --- a/planning/behavior_path_avoidance_module/config/avoidance.param.yaml +++ b/planning/behavior_path_avoidance_module/config/avoidance.param.yaml @@ -19,6 +19,7 @@ use_opposite_lane: true use_intersection_areas: true use_hatched_road_markings: true + use_freespace_areas: true # for debug publish_debug_marker: false diff --git a/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/data_structs.hpp b/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/data_structs.hpp index 9b5ae3cb4db9e..5e162a17a5064 100644 --- a/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/data_structs.hpp +++ b/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/data_structs.hpp @@ -115,6 +115,9 @@ struct AvoidanceParameters // use intersection area for avoidance bool use_intersection_areas{false}; + // use freespace area for avoidance + bool use_freespace_areas{false}; + // consider avoidance return dead line bool enable_dead_line_for_goal{false}; bool enable_dead_line_for_traffic_light{false}; diff --git a/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/parameter_helper.hpp b/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/parameter_helper.hpp index 9f2fdf7ab96d9..03902e4328eb2 100644 --- a/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/parameter_helper.hpp +++ b/planning/behavior_path_avoidance_module/include/behavior_path_avoidance_module/parameter_helper.hpp @@ -57,6 +57,7 @@ AvoidanceParameters getParameter(rclcpp::Node * node) p.use_intersection_areas = getOrDeclareParameter(*node, ns + "use_intersection_areas"); p.use_hatched_road_markings = getOrDeclareParameter(*node, ns + "use_hatched_road_markings"); + p.use_freespace_areas = getOrDeclareParameter(*node, ns + "use_freespace_areas"); } // target object diff --git a/planning/behavior_path_avoidance_module/src/scene.cpp b/planning/behavior_path_avoidance_module/src/scene.cpp index bc1d8c6d75424..7cea678fb8b03 100644 --- a/planning/behavior_path_avoidance_module/src/scene.cpp +++ b/planning/behavior_path_avoidance_module/src/scene.cpp @@ -235,11 +235,13 @@ void AvoidanceModule::fillFundamentalData(AvoidancePlanningData & data, DebugDat auto tmp_path = getPreviousModuleOutput().path; const auto shorten_lanes = utils::cutOverlappedLanes(tmp_path, data.drivable_lanes); data.left_bound = toLineString3d(utils::calcBound( - planner_data_->route_handler, shorten_lanes, parameters_->use_hatched_road_markings, - parameters_->use_intersection_areas, true)); + getPreviousModuleOutput().path, planner_data_, shorten_lanes, + parameters_->use_hatched_road_markings, parameters_->use_intersection_areas, + parameters_->use_freespace_areas, true)); data.right_bound = toLineString3d(utils::calcBound( - planner_data_->route_handler, shorten_lanes, parameters_->use_hatched_road_markings, - parameters_->use_intersection_areas, false)); + getPreviousModuleOutput().path, planner_data_, shorten_lanes, + parameters_->use_hatched_road_markings, parameters_->use_intersection_areas, + parameters_->use_freespace_areas, false)); // reference path if (isDrivingSameLane(helper_->getPreviousDrivingLanes(), data.current_lanelets)) { @@ -938,6 +940,8 @@ BehaviorModuleOutput AvoidanceModule::plan() // expand intersection areas current_drivable_area_info.enable_expanding_intersection_areas = parameters_->use_intersection_areas; + // expand freespace areas + current_drivable_area_info.enable_expanding_freespace_areas = parameters_->use_freespace_areas; output.drivable_area_info = utils::combineDrivableAreaInfo( current_drivable_area_info, getPreviousModuleOutput().drivable_area_info); diff --git a/planning/behavior_path_planner/src/planner_manager.cpp b/planning/behavior_path_planner/src/planner_manager.cpp index 4caf5683f3982..c60bc53a1129e 100644 --- a/planning/behavior_path_planner/src/planner_manager.cpp +++ b/planning/behavior_path_planner/src/planner_manager.cpp @@ -226,8 +226,7 @@ void PlannerManager::generateCombinedDrivableArea( } else if (di.is_already_expanded) { // for single side shift utils::generateDrivableArea( - output.path, di.drivable_lanes, false, false, data->parameters.vehicle_length, data, - is_driving_forward); + output.path, di.drivable_lanes, false, false, false, data, is_driving_forward); } else { const auto shorten_lanes = utils::cutOverlappedLanes(output.path, di.drivable_lanes); @@ -239,7 +238,7 @@ void PlannerManager::generateCombinedDrivableArea( // for other modules where multiple modules may be launched utils::generateDrivableArea( output.path, expanded_lanes, di.enable_expanding_hatched_road_markings, - di.enable_expanding_intersection_areas, data->parameters.vehicle_length, data, + di.enable_expanding_intersection_areas, di.enable_expanding_freespace_areas, data, is_driving_forward); } diff --git a/planning/behavior_path_planner_common/include/behavior_path_planner_common/data_manager.hpp b/planning/behavior_path_planner_common/include/behavior_path_planner_common/data_manager.hpp index 31dc117fbce35..28943b5724fe8 100644 --- a/planning/behavior_path_planner_common/include/behavior_path_planner_common/data_manager.hpp +++ b/planning/behavior_path_planner_common/include/behavior_path_planner_common/data_manager.hpp @@ -106,6 +106,7 @@ struct DrivableAreaInfo std::vector obstacles{}; // obstacles to extract from the drivable area bool enable_expanding_hatched_road_markings{false}; bool enable_expanding_intersection_areas{false}; + bool enable_expanding_freespace_areas{false}; // temporary only for pull over's freespace planning double drivable_margin{0.0}; diff --git a/planning/behavior_path_planner_common/include/behavior_path_planner_common/utils/drivable_area_expansion/static_drivable_area.hpp b/planning/behavior_path_planner_common/include/behavior_path_planner_common/utils/drivable_area_expansion/static_drivable_area.hpp index 9053da45708a0..9afa2608e1db6 100644 --- a/planning/behavior_path_planner_common/include/behavior_path_planner_common/utils/drivable_area_expansion/static_drivable_area.hpp +++ b/planning/behavior_path_planner_common/include/behavior_path_planner_common/utils/drivable_area_expansion/static_drivable_area.hpp @@ -19,6 +19,7 @@ #include #include +#include #include namespace behavior_path_planner::utils { @@ -40,8 +41,8 @@ std::vector getNonOverlappingExpandedLanes( void generateDrivableArea( PathWithLaneId & path, const std::vector & lanes, const bool enable_expanding_hatched_road_markings, const bool enable_expanding_intersection_areas, - const double vehicle_length, const std::shared_ptr planner_data, - const bool is_driving_forward = true); + const bool enable_expanding_freespace_areas, + const std::shared_ptr planner_data, const bool is_driving_forward = true); void generateDrivableArea( PathWithLaneId & path, const double vehicle_length, const double offset, @@ -62,6 +63,11 @@ std::vector expandLanelets( void extractObstaclesFromDrivableArea( PathWithLaneId & path, const std::vector & obstacles); +std::pair, bool> getBoundWithFreeSpaceAreas( + const std::vector & original_bound, + const std::vector & other_side_bound, + const std::shared_ptr planner_data, const bool is_left); + std::vector getBoundWithHatchedRoadMarkings( const std::vector & original_bound, const std::shared_ptr & route_handler); @@ -72,14 +78,22 @@ std::vector getBoundWithIntersectionAreas( const std::vector & drivable_lanes, const bool is_left); std::vector calcBound( - const std::shared_ptr route_handler, + const PathWithLaneId & path, const std::shared_ptr planner_data, + const std::vector & drivable_lanes, + const bool enable_expanding_hatched_road_markings, const bool enable_expanding_intersection_areas, + const bool enable_expanding_freespace_areas, const bool is_left, + const bool is_driving_forward = true); + +std::vector postProcess( + const std::vector & original_bound, const PathWithLaneId & path, + const std::shared_ptr planner_data, const std::vector & drivable_lanes, const bool enable_expanding_hatched_road_markings, const bool enable_expanding_intersection_areas, - const bool is_left); + const bool is_left, const bool is_driving_forward = true); -void makeBoundLongitudinallyMonotonic( - PathWithLaneId & path, const std::shared_ptr & planner_data, - const bool is_bound_left); +std::vector makeBoundLongitudinallyMonotonic( + const std::vector & original_bound, const PathWithLaneId & path, + const std::shared_ptr & planner_data, const bool is_left); DrivableAreaInfo combineDrivableAreaInfo( const DrivableAreaInfo & drivable_area_info1, const DrivableAreaInfo & drivable_area_info2); diff --git a/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp b/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp index 4e25e9257ddfd..18627e8396239 100644 --- a/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp +++ b/planning/behavior_path_planner_common/src/utils/drivable_area_expansion/static_drivable_area.cpp @@ -154,6 +154,7 @@ std::vector extractBoundFromPolygon( const bool clockwise) { std::vector ret{}; + for (size_t i = start_idx; i != end_idx; i = clockwise ? i + 1 : i - 1) { ret.push_back(polygon[i]); @@ -765,54 +766,27 @@ std::vector getNonOverlappingExpandedLanes( void generateDrivableArea( PathWithLaneId & path, const std::vector & lanes, const bool enable_expanding_hatched_road_markings, const bool enable_expanding_intersection_areas, - const double vehicle_length, const std::shared_ptr planner_data, - const bool is_driving_forward) + const bool enable_expanding_freespace_areas, + const std::shared_ptr planner_data, const bool is_driving_forward) { - // extract data - const auto transformed_lanes = utils::transformToLanelets(lanes); - const auto current_pose = planner_data->self_odometry->pose.pose; - const auto route_handler = planner_data->route_handler; - constexpr double overlap_threshold = 0.01; - if (path.points.empty()) { return; } - auto addPoints = - [](const lanelet::ConstLineString3d & points, std::vector & bound) { - for (const auto & bound_p : points) { - const auto cp = lanelet::utils::conversion::toGeomMsgPt(bound_p); - if (bound.empty()) { - bound.push_back(cp); - } else if (tier4_autoware_utils::calcDistance2d(cp, bound.back()) > overlap_threshold) { - bound.push_back(cp); - } - } - }; - - const auto has_overlap = - [&](const lanelet::ConstLanelet & lane, const lanelet::ConstLanelets & ignore_lanelets = {}) { - for (const auto & transformed_lane : transformed_lanes) { - if (checkHasSameLane(ignore_lanelets, transformed_lane)) { - continue; - } - if (boost::geometry::intersects( - lane.polygon2d().basicPolygon(), transformed_lane.polygon2d().basicPolygon())) { - return true; - } - } - return false; - }; + path.left_bound.clear(); + path.right_bound.clear(); // Insert Position - auto left_bound = calcBound( - route_handler, lanes, enable_expanding_hatched_road_markings, - enable_expanding_intersection_areas, true); - auto right_bound = calcBound( - route_handler, lanes, enable_expanding_hatched_road_markings, - enable_expanding_intersection_areas, false); - - if (left_bound.empty() || right_bound.empty()) { + path.left_bound = calcBound( + path, planner_data, lanes, enable_expanding_hatched_road_markings, + enable_expanding_intersection_areas, enable_expanding_freespace_areas, true, + is_driving_forward); + path.right_bound = calcBound( + path, planner_data, lanes, enable_expanding_hatched_road_markings, + enable_expanding_intersection_areas, enable_expanding_freespace_areas, false, + is_driving_forward); + + if (path.left_bound.empty() || path.right_bound.empty()) { auto clock{rclcpp::Clock{RCL_ROS_TIME}}; RCLCPP_ERROR_STREAM_THROTTLE( rclcpp::get_logger("behavior_path_planner").get_child("utils"), clock, 1000, @@ -820,135 +794,10 @@ void generateDrivableArea( return; } - // Insert points after goal - lanelet::ConstLanelet goal_lanelet; - if ( - route_handler->getGoalLanelet(&goal_lanelet) && - checkHasSameLane(transformed_lanes, goal_lanelet)) { - const auto lanes_after_goal = route_handler->getLanesAfterGoal(vehicle_length); - const auto next_lanes_after_goal = route_handler->getNextLanelets(goal_lanelet); - const auto goal_left_lanelet = route_handler->getLeftLanelet(goal_lanelet); - const auto goal_right_lanelet = route_handler->getRightLanelet(goal_lanelet); - lanelet::ConstLanelets goal_lanelets = {goal_lanelet}; - if (goal_left_lanelet) { - goal_lanelets.push_back(*goal_left_lanelet); - } - if (goal_right_lanelet) { - goal_lanelets.push_back(*goal_right_lanelet); - } - - for (const auto & lane : lanes_after_goal) { - // If lane is already in the transformed lanes, ignore it - if (checkHasSameLane(transformed_lanes, lane)) { - continue; - } - // Check if overlapped - const bool is_overlapped = - (checkHasSameLane(next_lanes_after_goal, lane) ? has_overlap(lane, goal_lanelets) - : has_overlap(lane)); - if (is_overlapped) { - continue; - } - - addPoints(lane.leftBound3d(), left_bound); - addPoints(lane.rightBound3d(), right_bound); - } - } - - if (!is_driving_forward) { - std::reverse(left_bound.begin(), left_bound.end()); - std::reverse(right_bound.begin(), right_bound.end()); - } - - path.left_bound.clear(); - path.right_bound.clear(); - - const auto [left_start_idx, right_start_idx] = [&]() { - const size_t current_seg_idx = planner_data->findEgoSegmentIndex(path.points); - const auto cropped_path_points = motion_utils::cropPoints( - path.points, current_pose.position, current_seg_idx, - planner_data->parameters.forward_path_length, - planner_data->parameters.backward_path_length + planner_data->parameters.input_path_interval); - - constexpr double front_length = 0.5; - const auto front_pose = - cropped_path_points.empty() ? current_pose : cropped_path_points.front().point.pose; - const size_t front_left_start_idx = - findNearestSegmentIndexFromLateralDistance(left_bound, front_pose, M_PI_2); - const size_t front_right_start_idx = - findNearestSegmentIndexFromLateralDistance(right_bound, front_pose, M_PI_2); - const auto left_start_point = - calcLongitudinalOffsetStartPoint(left_bound, front_pose, front_left_start_idx, -front_length); - const auto right_start_point = calcLongitudinalOffsetStartPoint( - right_bound, front_pose, front_right_start_idx, -front_length); - const size_t left_start_idx = - findNearestSegmentIndexFromLateralDistance(left_bound, left_start_point); - const size_t right_start_idx = - findNearestSegmentIndexFromLateralDistance(right_bound, right_start_point); - - // Insert a start point - path.left_bound.push_back(left_start_point); - path.right_bound.push_back(right_start_point); - - return std::make_pair(left_start_idx, right_start_idx); - }(); - - // Get Closest segment for the goal point - const auto goal_pose = path.points.empty() ? current_pose : path.points.back().point.pose; - const size_t goal_left_start_idx = - findNearestSegmentIndexFromLateralDistance(left_bound, goal_pose, M_PI_2); - const size_t goal_right_start_idx = - findNearestSegmentIndexFromLateralDistance(right_bound, goal_pose, M_PI_2); - const auto left_goal_point = - calcLongitudinalOffsetGoalPoint(left_bound, goal_pose, goal_left_start_idx, vehicle_length); - const auto right_goal_point = - calcLongitudinalOffsetGoalPoint(right_bound, goal_pose, goal_right_start_idx, vehicle_length); - const size_t left_goal_idx = std::max( - goal_left_start_idx, findNearestSegmentIndexFromLateralDistance(left_bound, left_goal_point)); - const size_t right_goal_idx = std::max( - goal_right_start_idx, - findNearestSegmentIndexFromLateralDistance(right_bound, right_goal_point)); - - // Insert middle points - for (size_t i = left_start_idx + 1; i <= left_goal_idx; ++i) { - const auto & next_point = left_bound.at(i); - const double dist = tier4_autoware_utils::calcDistance2d(path.left_bound.back(), next_point); - if (dist > overlap_threshold) { - path.left_bound.push_back(next_point); - } - } - for (size_t i = right_start_idx + 1; i <= right_goal_idx; ++i) { - const auto & next_point = right_bound.at(i); - const double dist = tier4_autoware_utils::calcDistance2d(path.right_bound.back(), next_point); - if (dist > overlap_threshold) { - path.right_bound.push_back(next_point); - } - } - - // Insert a goal point - if ( - tier4_autoware_utils::calcDistance2d(path.left_bound.back(), left_goal_point) > - overlap_threshold) { - path.left_bound.push_back(left_goal_point); - } - if ( - tier4_autoware_utils::calcDistance2d(path.right_bound.back(), right_goal_point) > - overlap_threshold) { - path.right_bound.push_back(right_goal_point); - } const auto & expansion_params = planner_data->drivable_area_expansion_parameters; if (expansion_params.enabled) { drivable_area_expansion::expand_drivable_area(path, planner_data); } - - // make bound longitudinally monotonic - // TODO(Murooka) Fix makeBoundLongitudinallyMonotonic - if ( - is_driving_forward && - (enable_expanding_hatched_road_markings || enable_expanding_intersection_areas)) { - makeBoundLongitudinallyMonotonic(path, planner_data, true); // for left bound - makeBoundLongitudinallyMonotonic(path, planner_data, false); // for right bound - } } void generateDrivableArea( @@ -1400,15 +1249,333 @@ std::vector getBoundWithIntersectionAreas( return expanded_bound; } +std::pair, bool> getBoundWithFreeSpaceAreas( + const std::vector & original_bound, + const std::vector & other_side_bound, + const std::shared_ptr planner_data, const bool is_left) +{ + using lanelet::utils::to2D; + using lanelet::utils::conversion::toGeomMsgPt; + using lanelet::utils::conversion::toLaneletPoint; + using tier4_autoware_utils::getPose; + using tier4_autoware_utils::pose2transform; + using tier4_autoware_utils::transformVector; + + const auto & route_handler = planner_data->route_handler; + const auto & ego_pose = planner_data->self_odometry->pose.pose; + + auto polygons = lanelet::utils::query::getAllParkingLots(route_handler->getLaneletMapPtr()); + if (polygons.empty()) { + return std::make_pair(original_bound, false); + } + + std::sort(polygons.begin(), polygons.end(), [&ego_pose](const auto & a, const auto & b) { + const double a_distance = boost::geometry::distance( + to2D(a).basicPolygon(), to2D(toLaneletPoint(ego_pose.position)).basicPoint()); + const double b_distance = boost::geometry::distance( + to2D(b).basicPolygon(), to2D(toLaneletPoint(ego_pose.position)).basicPoint()); + return a_distance < b_distance; + }); + + const auto & polygon = polygons.front(); + + const auto original_bound_itr = + std::find_if(original_bound.begin(), original_bound.end(), [&polygon](const auto & p) { + return std::any_of(polygon.begin(), polygon.end(), [&p](const auto & p_outer) { + return p.id() == p_outer.id(); + }); + }); + + const auto original_bound_rev_itr = + std::find_if(original_bound.rbegin(), original_bound.rend(), [&polygon](const auto & p) { + return std::any_of(polygon.begin(), polygon.end(), [&p](const auto & p_outer) { + return p.id() == p_outer.id(); + }); + }); + + const auto other_side_bound_itr = + std::find_if(other_side_bound.begin(), other_side_bound.end(), [&polygon](const auto & p) { + return std::any_of(polygon.begin(), polygon.end(), [&p](const auto & p_outer) { + return p.id() == p_outer.id(); + }); + }); + + if ( + original_bound_itr == original_bound.end() || other_side_bound_itr == other_side_bound.end()) { + return std::make_pair(original_bound, false); + } + + const auto footprint = planner_data->parameters.vehicle_info.createFootprint(); + const auto vehicle_polygon = transformVector(footprint, pose2transform(ego_pose)); + const auto is_driving_freespace = + !boost::geometry::disjoint(vehicle_polygon, to2D(polygon).basicPolygon()); + + const auto is_clockwise_polygon = boost::geometry::is_valid(to2D(polygon.basicPolygon())); + const auto is_clockwise_iteration = is_clockwise_polygon ? is_left : !is_left; + + const auto extract_bound_from_polygon = [&polygon, &is_clockwise_iteration]( + const auto & start_id, const auto & end_id) { + const auto start_point_itr = std::find_if( + polygon.begin(), polygon.end(), [&](const auto & p) { return p.id() == start_id; }); + + const auto end_point_itr = std::find_if( + polygon.begin(), polygon.end(), [&](const auto & p) { return p.id() == end_id; }); + + // extract line strings between start_idx and end_idx. + const size_t start_idx = std::distance(polygon.begin(), start_point_itr); + const size_t end_idx = std::distance(polygon.begin(), end_point_itr); + + return extractBoundFromPolygon(polygon, start_idx, end_idx, is_clockwise_iteration); + }; + + const auto get_bound_edge = [&ego_pose, &is_driving_freespace, &is_left]( + const auto & bound, const auto trim_behind_bound) { + if (!is_driving_freespace) { + return bound; + } + + const auto p_offset = tier4_autoware_utils::calcOffsetPose( + ego_pose, (trim_behind_bound ? -100.0 : 100.0), (is_left ? 0.1 : -0.1), 0.0); + + std::vector ret; + for (size_t i = 1; i < bound.size(); ++i) { + const auto intersect = tier4_autoware_utils::intersect( + ego_pose.position, p_offset.position, toGeomMsgPt(bound.at(i - 1)), + toGeomMsgPt(bound.at(i))); + + ret.push_back(bound.at(i - 1)); + + if (intersect.has_value()) { + ret.emplace_back( + lanelet::InvalId, intersect.value().x, intersect.value().y, intersect.value().z); + break; + } + } + + return ret; + }; + + std::vector expanded_bound; + + enum class RouteCase { + ROUTE_IS_PASS_THROUGH_FREESPACE = 0, + GOAL_POS_IS_IN_FREESPACE, + INIT_POS_IS_IN_FREESPACE, + OTHER, + }; + + const auto route_case = [&]() { + if (original_bound_itr->id() != original_bound_rev_itr->id()) { + return RouteCase::ROUTE_IS_PASS_THROUGH_FREESPACE; + } else if (boost::geometry::within( + to2D(original_bound.front().basicPoint()), to2D(polygon).basicPolygon())) { + return RouteCase::INIT_POS_IS_IN_FREESPACE; + } else if (boost::geometry::within( + to2D(original_bound.back().basicPoint()), to2D(polygon).basicPolygon())) { + return RouteCase::GOAL_POS_IS_IN_FREESPACE; + } + return RouteCase::OTHER; + }(); + + switch (route_case) { + case RouteCase::ROUTE_IS_PASS_THROUGH_FREESPACE: { + const auto polygon_bound = + extract_bound_from_polygon(original_bound_itr->id(), original_bound_rev_itr->id()); + + expanded_bound.insert(expanded_bound.end(), original_bound.begin(), original_bound_itr); + expanded_bound.insert(expanded_bound.end(), polygon_bound.begin(), polygon_bound.end()); + expanded_bound.insert( + expanded_bound.end(), std::next(original_bound_rev_itr).base(), original_bound.end()); + break; + } + case RouteCase::INIT_POS_IS_IN_FREESPACE: { + auto polygon_bound = + extract_bound_from_polygon(other_side_bound_itr->id(), original_bound_itr->id()); + std::reverse(polygon_bound.begin(), polygon_bound.end()); + auto bound_edge = get_bound_edge(polygon_bound, true); + std::reverse(bound_edge.begin(), bound_edge.end()); + + expanded_bound.insert(expanded_bound.end(), bound_edge.begin(), bound_edge.end()); + expanded_bound.insert(expanded_bound.end(), original_bound_itr, original_bound.end()); + break; + } + case RouteCase::GOAL_POS_IS_IN_FREESPACE: { + const auto polygon_bound = + extract_bound_from_polygon(original_bound_itr->id(), other_side_bound_itr->id()); + const auto bound_edge = get_bound_edge(polygon_bound, false); + + expanded_bound.insert(expanded_bound.end(), original_bound.begin(), original_bound_itr); + expanded_bound.insert(expanded_bound.end(), bound_edge.begin(), bound_edge.end()); + break; + } + case RouteCase::OTHER: { + expanded_bound = original_bound; + break; + } + default: + throw std::domain_error("invalid case."); + } + + const auto goal_is_in_freespace = boost::geometry::within( + to2D(toLaneletPoint(route_handler->getGoalPose().position).basicPoint()), + to2D(polygon).basicPolygon()); + + return std::make_pair(expanded_bound, is_driving_freespace || goal_is_in_freespace); +} + +std::vector postProcess( + const std::vector & original_bound, const PathWithLaneId & path, + const std::shared_ptr planner_data, + const std::vector & drivable_lanes, + const bool enable_expanding_hatched_road_markings, const bool enable_expanding_intersection_areas, + const bool is_left, const bool is_driving_forward) +{ + const auto lanelets = utils::transformToLanelets(drivable_lanes); + const auto & current_pose = planner_data->self_odometry->pose.pose; + const auto & route_handler = planner_data->route_handler; + const auto & vehicle_length = planner_data->parameters.vehicle_length; + constexpr double overlap_threshold = 0.01; + + const auto addPoints = + [](const lanelet::ConstLineString3d & points, std::vector & bound) { + for (const auto & bound_p : points) { + const auto cp = lanelet::utils::conversion::toGeomMsgPt(bound_p); + if (bound.empty()) { + bound.push_back(cp); + } else if (tier4_autoware_utils::calcDistance2d(cp, bound.back()) > overlap_threshold) { + bound.push_back(cp); + } + } + }; + + const auto has_overlap = + [&](const lanelet::ConstLanelet & lane, const lanelet::ConstLanelets & ignore_lanelets = {}) { + for (const auto & transformed_lane : lanelets) { + if (checkHasSameLane(ignore_lanelets, transformed_lane)) { + continue; + } + if (boost::geometry::intersects( + lane.polygon2d().basicPolygon(), transformed_lane.polygon2d().basicPolygon())) { + return true; + } + } + return false; + }; + + std::vector processed_bound; + std::vector tmp_bound = original_bound; + + // Insert points after goal + lanelet::ConstLanelet goal_lanelet; + if (route_handler->getGoalLanelet(&goal_lanelet) && checkHasSameLane(lanelets, goal_lanelet)) { + const auto lanes_after_goal = route_handler->getLanesAfterGoal(vehicle_length); + const auto next_lanes_after_goal = route_handler->getNextLanelets(goal_lanelet); + const auto goal_left_lanelet = route_handler->getLeftLanelet(goal_lanelet); + const auto goal_right_lanelet = route_handler->getRightLanelet(goal_lanelet); + lanelet::ConstLanelets goal_lanelets = {goal_lanelet}; + if (goal_left_lanelet.has_value()) { + goal_lanelets.push_back(goal_left_lanelet.value()); + } + if (goal_right_lanelet.has_value()) { + goal_lanelets.push_back(goal_right_lanelet.value()); + } + + for (const auto & lane : lanes_after_goal) { + // If lane is already in the transformed lanes, ignore it + if (checkHasSameLane(lanelets, lane)) { + continue; + } + // Check if overlapped + const bool is_overlapped = + (checkHasSameLane(next_lanes_after_goal, lane) ? has_overlap(lane, goal_lanelets) + : has_overlap(lane)); + if (is_overlapped) { + continue; + } + + if (is_left) { + addPoints(lane.leftBound3d(), tmp_bound); + } else { + addPoints(lane.rightBound3d(), tmp_bound); + } + } + } + + if (!is_driving_forward) { + std::reverse(tmp_bound.begin(), tmp_bound.end()); + } + + const auto start_idx = [&]() { + const size_t current_seg_idx = planner_data->findEgoSegmentIndex(path.points); + const auto cropped_path_points = motion_utils::cropPoints( + path.points, current_pose.position, current_seg_idx, + planner_data->parameters.forward_path_length, + planner_data->parameters.backward_path_length + planner_data->parameters.input_path_interval); + + constexpr double front_length = 0.5; + const auto front_pose = + cropped_path_points.empty() ? current_pose : cropped_path_points.front().point.pose; + const size_t front_start_idx = + findNearestSegmentIndexFromLateralDistance(tmp_bound, front_pose, M_PI_2); + const auto start_point = + calcLongitudinalOffsetStartPoint(tmp_bound, front_pose, front_start_idx, -front_length); + + // Insert a start point + processed_bound.push_back(start_point); + + return findNearestSegmentIndexFromLateralDistance(tmp_bound, start_point); + }(); + + // Get Closest segment for the goal point + const auto [goal_idx, goal_point] = [&]() { + const auto goal_pose = path.points.empty() ? current_pose : path.points.back().point.pose; + const size_t goal_start_idx = + findNearestSegmentIndexFromLateralDistance(tmp_bound, goal_pose, M_PI_2); + const auto goal_point = + calcLongitudinalOffsetGoalPoint(tmp_bound, goal_pose, goal_start_idx, vehicle_length); + const size_t goal_idx = + std::max(goal_start_idx, findNearestSegmentIndexFromLateralDistance(tmp_bound, goal_point)); + + return std::make_pair(goal_idx, goal_point); + }(); + + // Insert middle points + for (size_t i = start_idx + 1; i <= goal_idx; ++i) { + const auto & next_point = tmp_bound.at(i); + const double dist = tier4_autoware_utils::calcDistance2d(processed_bound.back(), next_point); + if (dist > overlap_threshold) { + processed_bound.push_back(next_point); + } + } + + // Insert a goal point + if ( + tier4_autoware_utils::calcDistance2d(processed_bound.back(), goal_point) > overlap_threshold) { + processed_bound.push_back(goal_point); + } + + const bool skip_monotonic_process = + !is_driving_forward || + !(enable_expanding_hatched_road_markings || enable_expanding_intersection_areas); + + return skip_monotonic_process + ? processed_bound + : makeBoundLongitudinallyMonotonic(processed_bound, path, planner_data, is_left); +} + // calculate bounds from drivable lanes and hatched road markings std::vector calcBound( - const std::shared_ptr route_handler, + const PathWithLaneId & path, const std::shared_ptr planner_data, const std::vector & drivable_lanes, const bool enable_expanding_hatched_road_markings, const bool enable_expanding_intersection_areas, - const bool is_left) + const bool enable_expanding_freespace_areas, const bool is_left, const bool is_driving_forward) { + using motion_utils::removeOverlapPoints; + + const auto & route_handler = planner_data->route_handler; + // a function to convert drivable lanes to points without duplicated points - const auto convert_to_points = [&](const std::vector & drivable_lanes) { + const auto convert_to_points = [](const auto & drivable_lanes, const auto is_left) { constexpr double overlap_threshold = 0.01; std::vector points; @@ -1435,20 +1602,35 @@ std::vector calcBound( }; // Step1. create drivable bound from drivable lanes. - std::vector bound_points = convert_to_points(drivable_lanes); + auto [bound_points, skip_post_process] = [&]() { + if (!enable_expanding_freespace_areas) { + return std::make_pair(convert_to_points(drivable_lanes, is_left), false); + } + return getBoundWithFreeSpaceAreas( + convert_to_points(drivable_lanes, is_left), convert_to_points(drivable_lanes, !is_left), + planner_data, is_left); + }(); + + const auto post_process = [&](const auto & bound, const auto skip) { + return skip + ? bound + : postProcess( + bound, path, planner_data, drivable_lanes, enable_expanding_hatched_road_markings, + enable_expanding_intersection_areas, is_left, is_driving_forward); + }; // Step2. if there is no drivable area defined by polygon, return original drivable bound. if (!enable_expanding_hatched_road_markings && !enable_expanding_intersection_areas) { - return motion_utils::removeOverlapPoints(to_ros_point(bound_points)); + return post_process(removeOverlapPoints(to_ros_point(bound_points)), skip_post_process); } - // Step3. if there are hatched road markings, expand drivable bound with the polygon. + // Step3.if there are hatched road markings, expand drivable bound with the polygon. if (enable_expanding_hatched_road_markings) { bound_points = getBoundWithHatchedRoadMarkings(bound_points, route_handler); } if (!enable_expanding_intersection_areas) { - return motion_utils::removeOverlapPoints(to_ros_point(bound_points)); + return post_process(removeOverlapPoints(to_ros_point(bound_points)), skip_post_process); } // Step4. if there are intersection areas, expand drivable bound with the polygon. @@ -1457,12 +1639,12 @@ std::vector calcBound( getBoundWithIntersectionAreas(bound_points, route_handler, drivable_lanes, is_left); } - return motion_utils::removeOverlapPoints(to_ros_point(bound_points)); + return post_process(removeOverlapPoints(to_ros_point(bound_points)), skip_post_process); } -void makeBoundLongitudinallyMonotonic( - PathWithLaneId & path, const std::shared_ptr & planner_data, - const bool is_bound_left) +std::vector makeBoundLongitudinallyMonotonic( + const std::vector & original_bound, const PathWithLaneId & path, + const std::shared_ptr & planner_data, const bool is_left) { using motion_utils::findNearestSegmentIndex; using tier4_autoware_utils::calcAzimuthAngle; @@ -1508,7 +1690,7 @@ void makeBoundLongitudinallyMonotonic( const auto get_bound_with_pose = [&](const auto & bound_with_pose, const auto & path_points) { auto ret = bound_with_pose; - const double offset = is_bound_left ? 100.0 : -100.0; + const double offset = is_left ? 100.0 : -100.0; size_t start_bound_idx = 0; @@ -1588,14 +1770,14 @@ void makeBoundLongitudinallyMonotonic( // NOTE: is_bound_left is used instead of is_points_left since orientation of path point is // opposite. - const double lat_offset = is_bound_left ? 100.0 : -100.0; + const double lat_offset = is_left ? 100.0 : -100.0; const auto p_bound_1 = getPose(bound_with_pose.at(bound_idx)); const auto p_bound_2 = getPose(bound_with_pose.at(bound_idx + 1)); const auto p_bound_offset = calcOffsetPose(p_bound_1, 0.0, lat_offset, 0.0); - if (!is_non_monotonic(p_bound_1, p_bound_2.position, is_bound_left, is_reverse)) { + if (!is_non_monotonic(p_bound_1, p_bound_2.position, is_left, is_reverse)) { bound_idx++; continue; } @@ -1681,18 +1863,16 @@ void makeBoundLongitudinallyMonotonic( return ret; }; - const auto original_bound = is_bound_left ? path.left_bound : path.right_bound; - if (path.points.empty()) { - return; + return original_bound; } - if (original_bound.empty()) { - return; + if (original_bound.size() < 2) { + return original_bound; } if (path.points.front().lane_ids.empty()) { - return; + return original_bound; } // step.1 create bound with pose vector. @@ -1734,14 +1914,14 @@ void makeBoundLongitudinallyMonotonic( p.forward_path_length, p); if (centerline_path.points.size() < 2) { - return; + return original_bound; } const auto ego_idx = planner_data->findEgoIndex(centerline_path.points); const auto end_idx = findNearestSegmentIndex(centerline_path.points, original_bound.back()); if (ego_idx >= end_idx) { - return; + return original_bound; } clipped_points.insert( @@ -1750,7 +1930,7 @@ void makeBoundLongitudinallyMonotonic( } if (clipped_points.empty()) { - return; + return original_bound; } // step.3 update bound pose by reference path pose. @@ -1771,11 +1951,7 @@ void makeBoundLongitudinallyMonotonic( auto full_monotonic_bound = remove_orientation(full_monotonic_bound_with_pose); // step.7 remove sharp bound points. - if (is_bound_left) { - path.left_bound = remove_sharp_points(full_monotonic_bound); - } else { - path.right_bound = remove_sharp_points(full_monotonic_bound); - } + return remove_sharp_points(full_monotonic_bound); } std::vector combineDrivableLanes( @@ -1785,7 +1961,9 @@ std::vector combineDrivableLanes( const auto has_same_lane = [](const lanelet::ConstLanelet & target_lane, const lanelet::ConstLanelets & lanes) { return std::find_if(lanes.begin(), lanes.end(), [&](const auto & ll) { - return ll.id() == target_lane.id(); + return ll.id() == target_lane.id() && + ll.rightBound3d().id() == target_lane.rightBound3d().id() && + ll.leftBound3d().id() == target_lane.leftBound3d().id(); }) != lanes.end(); }; @@ -1884,6 +2062,11 @@ DrivableAreaInfo combineDrivableAreaInfo( drivable_area_info1.enable_expanding_intersection_areas || drivable_area_info2.enable_expanding_intersection_areas; + // enable expanding freespace areas + combined_drivable_area_info.enable_expanding_freespace_areas = + drivable_area_info1.enable_expanding_freespace_areas || + drivable_area_info2.enable_expanding_freespace_areas; + // drivable margin combined_drivable_area_info.drivable_margin = std::max(drivable_area_info1.drivable_margin, drivable_area_info2.drivable_margin); From 5b918742a3994d9e97c2dfb3264c62461bdc70b5 Mon Sep 17 00:00:00 2001 From: kminoda <44218668+kminoda@users.noreply.github.com> Date: Mon, 29 Jan 2024 09:30:04 +0900 Subject: [PATCH 031/132] chore(object_range_splitter): rework parameters (#6159) * chore(object_range_splitter): add param file Signed-off-by: kminoda * fix arg name Signed-off-by: kminoda * feat: use param file from autoware.launch Signed-off-by: kminoda --------- Signed-off-by: kminoda --- .../launch/object_recognition/detection/detection.launch.xml | 4 +++- .../detection/detector/radar_detector.launch.xml | 4 ++-- launch/tier4_perception_launch/launch/perception.launch.xml | 2 ++ perception/object_range_splitter/CMakeLists.txt | 1 + .../config/object_range_splitter.param.yaml | 3 +++ .../launch/object_range_splitter.launch.xml | 4 ++-- 6 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 perception/object_range_splitter/config/object_range_splitter.param.yaml diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml index ab9ed65999048..78c6c585d90f7 100644 --- a/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/detection.launch.xml @@ -78,7 +78,7 @@ - + @@ -177,6 +177,7 @@ + @@ -236,6 +237,7 @@ + diff --git a/launch/tier4_perception_launch/launch/object_recognition/detection/detector/radar_detector.launch.xml b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/radar_detector.launch.xml index 26e7af07646cd..0ef0201d973e1 100644 --- a/launch/tier4_perception_launch/launch/object_recognition/detection/detector/radar_detector.launch.xml +++ b/launch/tier4_perception_launch/launch/object_recognition/detection/detector/radar_detector.launch.xml @@ -5,7 +5,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/launch/tier4_perception_launch/launch/perception.launch.xml b/launch/tier4_perception_launch/launch/perception.launch.xml index 528038c5158b2..3bd3aff10a4e4 100644 --- a/launch/tier4_perception_launch/launch/perception.launch.xml +++ b/launch/tier4_perception_launch/launch/perception.launch.xml @@ -16,6 +16,8 @@ + + diff --git a/perception/object_range_splitter/CMakeLists.txt b/perception/object_range_splitter/CMakeLists.txt index 7b27a344a5e0d..92c6c0668a085 100644 --- a/perception/object_range_splitter/CMakeLists.txt +++ b/perception/object_range_splitter/CMakeLists.txt @@ -16,4 +16,5 @@ rclcpp_components_register_node(object_range_splitter ament_auto_package( INSTALL_TO_SHARE launch + config ) diff --git a/perception/object_range_splitter/config/object_range_splitter.param.yaml b/perception/object_range_splitter/config/object_range_splitter.param.yaml new file mode 100644 index 0000000000000..45bde990029f3 --- /dev/null +++ b/perception/object_range_splitter/config/object_range_splitter.param.yaml @@ -0,0 +1,3 @@ +/**: + ros__parameters: + split_range: 30.0 diff --git a/perception/object_range_splitter/launch/object_range_splitter.launch.xml b/perception/object_range_splitter/launch/object_range_splitter.launch.xml index 6588c3e71ef73..3f2f3c6ba24c6 100644 --- a/perception/object_range_splitter/launch/object_range_splitter.launch.xml +++ b/perception/object_range_splitter/launch/object_range_splitter.launch.xml @@ -3,12 +3,12 @@ - + - + From f514bcaa06d2aef6e7d02b49262a3728e90b5b31 Mon Sep 17 00:00:00 2001 From: Mamoru Sobue Date: Mon, 29 Jan 2024 10:04:53 +0900 Subject: [PATCH 032/132] feat(intersection): publish and visualize the reason for dangerous situation to blame past detection fault retrospectively (#6143) Signed-off-by: Mamoru Sobue --- .../CMakeLists.txt | 2 + .../config/intersection.param.yaml | 2 + .../package.xml | 3 +- .../src/debug.cpp | 122 ++- .../src/decision_result.cpp | 65 ++ .../src/decision_result.hpp | 67 +- .../src/interpolated_path_info.hpp | 1 - .../src/intersection_lanelets.hpp | 2 - .../src/intersection_stoplines.hpp | 5 +- .../src/manager.cpp | 5 + .../src/object_manager.cpp | 309 ++++++++ .../src/object_manager.hpp | 294 +++++++ .../src/result.hpp | 17 +- .../src/scene_intersection.cpp | 559 ++++++------- .../src/scene_intersection.hpp | 233 +++--- .../src/scene_intersection_collision.cpp | 746 ++++++++++++++++-- .../src/scene_intersection_occlusion.cpp | 49 +- .../src/scene_intersection_prepare_data.cpp | 95 ++- .../src/scene_intersection_stuck.cpp | 26 +- .../src/util.hpp | 14 +- 20 files changed, 1928 insertions(+), 688 deletions(-) create mode 100644 planning/behavior_velocity_intersection_module/src/decision_result.cpp create mode 100644 planning/behavior_velocity_intersection_module/src/object_manager.cpp create mode 100644 planning/behavior_velocity_intersection_module/src/object_manager.hpp diff --git a/planning/behavior_velocity_intersection_module/CMakeLists.txt b/planning/behavior_velocity_intersection_module/CMakeLists.txt index 4c8fe5c6fa0f5..07847a08c1209 100644 --- a/planning/behavior_velocity_intersection_module/CMakeLists.txt +++ b/planning/behavior_velocity_intersection_module/CMakeLists.txt @@ -12,6 +12,8 @@ ament_auto_add_library(${PROJECT_NAME} SHARED src/util.cpp src/scene_intersection.cpp src/intersection_lanelets.cpp + src/object_manager.cpp + src/decision_result.cpp src/scene_intersection_prepare_data.cpp src/scene_intersection_stuck.cpp src/scene_intersection_occlusion.cpp diff --git a/planning/behavior_velocity_intersection_module/config/intersection.param.yaml b/planning/behavior_velocity_intersection_module/config/intersection.param.yaml index 108e021240851..c7f6f62d575a0 100644 --- a/planning/behavior_velocity_intersection_module/config/intersection.param.yaml +++ b/planning/behavior_velocity_intersection_module/config/intersection.param.yaml @@ -59,6 +59,8 @@ object_expected_deceleration: 2.0 ignore_on_red_traffic_light: object_margin_to_path: 2.0 + avoid_collision_by_acceleration: + object_time_margin_to_collision_point: 4.0 occlusion: enable: false diff --git a/planning/behavior_velocity_intersection_module/package.xml b/planning/behavior_velocity_intersection_module/package.xml index 0c9b3407d0f38..0bed7d32f412f 100644 --- a/planning/behavior_velocity_intersection_module/package.xml +++ b/planning/behavior_velocity_intersection_module/package.xml @@ -22,10 +22,12 @@ autoware_auto_planning_msgs autoware_perception_msgs behavior_velocity_planner_common + fmt geometry_msgs interpolation lanelet2_extension libopencv-dev + magic_enum motion_utils nav_msgs pluginlib @@ -33,7 +35,6 @@ route_handler rtc_interface tf2_geometry_msgs - tier4_api_msgs tier4_autoware_utils tier4_planning_msgs vehicle_info_util diff --git a/planning/behavior_velocity_intersection_module/src/debug.cpp b/planning/behavior_velocity_intersection_module/src/debug.cpp index 350f6d774f7cf..978855b36c5f6 100644 --- a/planning/behavior_velocity_intersection_module/src/debug.cpp +++ b/planning/behavior_velocity_intersection_module/src/debug.cpp @@ -31,8 +31,6 @@ #include #include -namespace behavior_velocity_planner -{ namespace { using tier4_autoware_utils::appendMarkerArray; @@ -40,14 +38,14 @@ using tier4_autoware_utils::createMarkerColor; using tier4_autoware_utils::createMarkerOrientation; using tier4_autoware_utils::createMarkerScale; -static visualization_msgs::msg::MarkerArray createLaneletPolygonsMarkerArray( +visualization_msgs::msg::MarkerArray createLaneletPolygonsMarkerArray( const std::vector & polygons, const std::string & ns, const int64_t lane_id, const double r, const double g, const double b) { visualization_msgs::msg::MarkerArray msg; int32_t i = 0; - int32_t uid = planning_utils::bitShift(lane_id); + int32_t uid = behavior_velocity_planner::planning_utils::bitShift(lane_id); for (const auto & polygon : polygons) { visualization_msgs::msg::Marker marker{}; marker.header.frame_id = "map"; @@ -158,8 +156,59 @@ visualization_msgs::msg::MarkerArray createLineMarkerArray( return marker_point; } +constexpr std::tuple white() +{ + constexpr uint64_t code = 0xfdfdfd; + constexpr float r = static_cast(code >> 16) / 255.0; + constexpr float g = static_cast((code << 48) >> 56) / 255.0; + constexpr float b = static_cast((code << 56) >> 56) / 255.0; + return {r, g, b}; +} + +constexpr std::tuple green() +{ + constexpr uint64_t code = 0x5fa641; + constexpr float r = static_cast(code >> 16) / 255.0; + constexpr float g = static_cast((code << 48) >> 56) / 255.0; + constexpr float b = static_cast((code << 56) >> 56) / 255.0; + return {r, g, b}; +} + +constexpr std::tuple yellow() +{ + constexpr uint64_t code = 0xebce2b; + constexpr float r = static_cast(code >> 16) / 255.0; + constexpr float g = static_cast((code << 48) >> 56) / 255.0; + constexpr float b = static_cast((code << 56) >> 56) / 255.0; + return {r, g, b}; +} + +constexpr std::tuple red() +{ + constexpr uint64_t code = 0xba1c30; + constexpr float r = static_cast(code >> 16) / 255.0; + constexpr float g = static_cast((code << 48) >> 56) / 255.0; + constexpr float b = static_cast((code << 56) >> 56) / 255.0; + return {r, g, b}; +} + +constexpr std::tuple light_blue() +{ + constexpr uint64_t code = 0x96cde6; + constexpr float r = static_cast(code >> 16) / 255.0; + constexpr float g = static_cast((code << 48) >> 56) / 255.0; + constexpr float b = static_cast((code << 56) >> 56) / 255.0; + return {r, g, b}; +} } // namespace +namespace behavior_velocity_planner +{ +using tier4_autoware_utils::appendMarkerArray; +using tier4_autoware_utils::createMarkerColor; +using tier4_autoware_utils::createMarkerOrientation; +using tier4_autoware_utils::createMarkerScale; + visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray() { visualization_msgs::msg::MarkerArray debug_marker_array; @@ -168,14 +217,14 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( if (debug_data_.attention_area) { appendMarkerArray( - createLaneletPolygonsMarkerArray( + ::createLaneletPolygonsMarkerArray( debug_data_.attention_area.value(), "attention_area", lane_id_, 0.0, 1.0, 0.0), &debug_marker_array); } if (debug_data_.occlusion_attention_area) { appendMarkerArray( - createLaneletPolygonsMarkerArray( + ::createLaneletPolygonsMarkerArray( debug_data_.occlusion_attention_area.value(), "occlusion_attention_area", lane_id_, 0.917, 0.568, 0.596), &debug_marker_array); @@ -183,14 +232,14 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( if (debug_data_.adjacent_area) { appendMarkerArray( - createLaneletPolygonsMarkerArray( + ::createLaneletPolygonsMarkerArray( debug_data_.adjacent_area.value(), "adjacent_area", lane_id_, 0.913, 0.639, 0.149), &debug_marker_array); } if (debug_data_.first_attention_area) { appendMarkerArray( - createLaneletPolygonsMarkerArray( + ::createLaneletPolygonsMarkerArray( {debug_data_.first_attention_area.value()}, "first_attention_area", lane_id_, 1, 0.647, 0.0), &debug_marker_array, now); @@ -198,7 +247,7 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( if (debug_data_.second_attention_area) { appendMarkerArray( - createLaneletPolygonsMarkerArray( + ::createLaneletPolygonsMarkerArray( {debug_data_.second_attention_area.value()}, "second_attention_area", lane_id_, 1, 0.647, 0.0), &debug_marker_array, now); @@ -214,7 +263,7 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( if (debug_data_.yield_stuck_detect_area) { appendMarkerArray( - createLaneletPolygonsMarkerArray( + ::createLaneletPolygonsMarkerArray( debug_data_.yield_stuck_detect_area.value(), "yield_stuck_detect_area", lane_id_, 0.6588235, 0.34509, 0.6588235), &debug_marker_array); @@ -222,7 +271,7 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( if (debug_data_.ego_lane) { appendMarkerArray( - createLaneletPolygonsMarkerArray( + ::createLaneletPolygonsMarkerArray( {debug_data_.ego_lane.value()}, "ego_lane", lane_id_, 1, 0.647, 0.0), &debug_marker_array, now); } @@ -235,59 +284,58 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( &debug_marker_array, now); } - size_t i{0}; - for (const auto & p : debug_data_.candidate_collision_object_polygons) { - appendMarkerArray( - debug::createPolygonMarkerArray( - p, "candidate_collision_object_polygons", lane_id_ + i++, now, 0.3, 0.0, 0.0, 0.0, 0.5, - 0.5), - &debug_marker_array, now); - } - + static constexpr auto white = ::white(); + static constexpr auto green = ::green(); + static constexpr auto yellow = ::yellow(); + static constexpr auto red = ::red(); + static constexpr auto light_blue = ::light_blue(); appendMarkerArray( debug::createObjectsMarkerArray( - debug_data_.conflicting_targets, "conflicting_targets", module_id_, now, 0.99, 0.4, 0.0), + debug_data_.safe_under_traffic_control_targets, "safe_under_traffic_control_targets", + module_id_, now, std::get<0>(light_blue), std::get<1>(light_blue), std::get<2>(light_blue)), &debug_marker_array, now); appendMarkerArray( debug::createObjectsMarkerArray( - debug_data_.amber_ignore_targets, "amber_ignore_targets", module_id_, now, 0.0, 1.0, 0.0), + debug_data_.unsafe_targets, "unsafe_targets", module_id_, now, std::get<0>(green), + std::get<1>(green), std::get<2>(green)), &debug_marker_array, now); appendMarkerArray( debug::createObjectsMarkerArray( - debug_data_.red_overshoot_ignore_targets, "red_overshoot_ignore_targets", module_id_, now, - 0.0, 1.0, 0.0), + debug_data_.misjudge_targets, "misjudge_targets", module_id_, now, std::get<0>(yellow), + std::get<1>(yellow), std::get<2>(yellow)), &debug_marker_array, now); appendMarkerArray( debug::createObjectsMarkerArray( - debug_data_.stuck_targets, "stuck_targets", module_id_, now, 0.99, 0.99, 0.2), + debug_data_.too_late_detect_targets, "too_late_detect_targets", module_id_, now, + std::get<0>(red), std::get<1>(red), std::get<2>(red)), &debug_marker_array, now); appendMarkerArray( debug::createObjectsMarkerArray( - debug_data_.yield_stuck_targets, "stuck_targets", module_id_, now, 0.4, 0.99, 0.2), + debug_data_.parked_targets, "parked_targets", module_id_, now, std::get<0>(white), + std::get<1>(white), std::get<2>(white)), &debug_marker_array, now); appendMarkerArray( debug::createObjectsMarkerArray( - debug_data_.blocking_attention_objects, "blocking_attention_objects", module_id_, now, 0.99, - 0.99, 0.6), + debug_data_.stuck_targets, "stuck_targets", module_id_, now, std::get<0>(white), + std::get<1>(white), std::get<2>(white)), &debug_marker_array, now); - /* appendMarkerArray( - createPoseMarkerArray( - debug_data_.predicted_obj_pose, "predicted_obj_pose", module_id_, 0.7, 0.85, 0.9), + debug::createObjectsMarkerArray( + debug_data_.yield_stuck_targets, "yield_stuck_targets", module_id_, now, std::get<0>(white), + std::get<1>(white), std::get<2>(white)), &debug_marker_array, now); - */ if (debug_data_.first_pass_judge_wall_pose) { const double r = debug_data_.passed_first_pass_judge ? 1.0 : 0.0; const double g = debug_data_.passed_first_pass_judge ? 0.0 : 1.0; appendMarkerArray( - createPoseMarkerArray( + ::createPoseMarkerArray( debug_data_.first_pass_judge_wall_pose.value(), "first_pass_judge_wall_pose", module_id_, r, g, 0.0), &debug_marker_array, now); @@ -297,7 +345,7 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( const double r = debug_data_.passed_second_pass_judge ? 1.0 : 0.0; const double g = debug_data_.passed_second_pass_judge ? 0.0 : 1.0; appendMarkerArray( - createPoseMarkerArray( + ::createPoseMarkerArray( debug_data_.second_pass_judge_wall_pose.value(), "second_pass_judge_wall_pose", module_id_, r, g, 0.0), &debug_marker_array, now); @@ -314,7 +362,7 @@ visualization_msgs::msg::MarkerArray IntersectionModule::createDebugMarkerArray( if (debug_data_.nearest_occlusion_projection) { const auto [point_start, point_end] = debug_data_.nearest_occlusion_projection.value(); appendMarkerArray( - createLineMarkerArray( + ::createLineMarkerArray( point_start, point_end, "nearest_occlusion_projection", lane_id_, 0.5, 0.5, 0.0), &debug_marker_array, now); } @@ -369,11 +417,11 @@ visualization_msgs::msg::MarkerArray MergeFromPrivateRoadModule::createDebugMark const auto state = state_machine_.getState(); - int32_t uid = planning_utils::bitShift(module_id_); + int32_t uid = behavior_velocity_planner::planning_utils::bitShift(module_id_); const auto now = this->clock_->now(); if (state == StateMachine::State::STOP) { appendMarkerArray( - createPoseMarkerArray(debug_data_.stop_point_pose, "stop_point_pose", uid, 1.0, 0.0, 0.0), + ::createPoseMarkerArray(debug_data_.stop_point_pose, "stop_point_pose", uid, 1.0, 0.0, 0.0), &debug_marker_array, now); } diff --git a/planning/behavior_velocity_intersection_module/src/decision_result.cpp b/planning/behavior_velocity_intersection_module/src/decision_result.cpp new file mode 100644 index 0000000000000..93a7c2a29d2f7 --- /dev/null +++ b/planning/behavior_velocity_intersection_module/src/decision_result.cpp @@ -0,0 +1,65 @@ +// 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. + +#include "decision_result.hpp" + +namespace behavior_velocity_planner::intersection +{ +std::string formatDecisionResult(const DecisionResult & decision_result) +{ + if (std::holds_alternative(decision_result)) { + const auto state = std::get(decision_result); + return "InternalError because " + state.error; + } + if (std::holds_alternative(decision_result)) { + const auto state = std::get(decision_result); + return "OverPassJudge:\nsafety_report:" + state.safety_report + "\nevasive_report:\n" + + state.evasive_report; + } + if (std::holds_alternative(decision_result)) { + return "StuckStop"; + } + if (std::holds_alternative(decision_result)) { + const auto state = std::get(decision_result); + return "YieldStuckStop:\nsafety_report:" + state.safety_report; + } + if (std::holds_alternative(decision_result)) { + const auto state = std::get(decision_result); + return "NonOccludedCollisionStop\nsafety_report:" + state.safety_report; + } + if (std::holds_alternative(decision_result)) { + return "FirstWaitBeforeOcclusion"; + } + if (std::holds_alternative(decision_result)) { + return "PeekingTowardOcclusion"; + } + if (std::holds_alternative(decision_result)) { + const auto state = std::get(decision_result); + return "OccludedCollisionStop\nsafety_report:" + state.safety_report; + } + if (std::holds_alternative(decision_result)) { + const auto state = std::get(decision_result); + return "OccludedAbsenceTrafficLight\nsafety_report:" + state.safety_report; + } + if (std::holds_alternative(decision_result)) { + return "Safe"; + } + if (std::holds_alternative(decision_result)) { + const auto state = std::get(decision_result); + return "FullyPrioritized\nsafety_report:" + state.safety_report; + } + return ""; +} + +} // namespace behavior_velocity_planner::intersection diff --git a/planning/behavior_velocity_intersection_module/src/decision_result.hpp b/planning/behavior_velocity_intersection_module/src/decision_result.hpp index 48b0ecf1349a5..da71168c2c4ca 100644 --- a/planning/behavior_velocity_intersection_module/src/decision_result.hpp +++ b/planning/behavior_velocity_intersection_module/src/decision_result.hpp @@ -23,16 +23,23 @@ namespace behavior_velocity_planner::intersection { /** - * @struct - * @brief Internal error or ego already passed pass_judge_line + * @brief internal error */ -struct Indecisive +struct InternalError { std::string error; }; /** - * @struct + * @brief + */ +struct OverPassJudge +{ + std::string safety_report; + std::string evasive_report; +}; + +/** * @brief detected stuck vehicle */ struct StuckStop @@ -43,17 +50,16 @@ struct StuckStop }; /** - * @struct * @brief yielded by vehicle on the attention area */ struct YieldStuckStop { size_t closest_idx{0}; size_t stuck_stopline_idx{0}; + std::string safety_report; }; /** - * @struct * @brief only collision is detected */ struct NonOccludedCollisionStop @@ -61,10 +67,10 @@ struct NonOccludedCollisionStop size_t closest_idx{0}; size_t collision_stopline_idx{0}; size_t occlusion_stopline_idx{0}; + std::string safety_report; }; /** - * @struct * @brief occlusion is detected so ego needs to stop at the default stop line position */ struct FirstWaitBeforeOcclusion @@ -76,7 +82,6 @@ struct FirstWaitBeforeOcclusion }; /** - * @struct * @brief ego is approaching the boundary of attention area in the presence of traffic light */ struct PeekingTowardOcclusion @@ -96,7 +101,6 @@ struct PeekingTowardOcclusion }; /** - * @struct * @brief both collision and occlusion are detected in the presence of traffic light */ struct OccludedCollisionStop @@ -110,10 +114,10 @@ struct OccludedCollisionStop //! if null, it is dynamic occlusion and shows up intersection_occlusion(dyn). if valid, it //! contains the remaining time to release the static occlusion stuck std::optional static_occlusion_timeout{std::nullopt}; + std::string safety_report; }; /** - * @struct * @brief at least occlusion is detected in the absence of traffic light */ struct OccludedAbsenceTrafficLight @@ -124,10 +128,10 @@ struct OccludedAbsenceTrafficLight size_t closest_idx{0}; size_t first_attention_area_stopline_idx{0}; size_t peeking_limit_line_idx{0}; + std::string safety_report; }; /** - * @struct * @brief both collision and occlusion are not detected */ struct Safe @@ -138,7 +142,6 @@ struct Safe }; /** - * @struct * @brief traffic light is red or arrow signal */ struct FullyPrioritized @@ -147,10 +150,12 @@ struct FullyPrioritized size_t closest_idx{0}; size_t collision_stopline_idx{0}; size_t occlusion_stopline_idx{0}; + std::string safety_report; }; using DecisionResult = std::variant< - Indecisive, //! internal process error, or over the pass judge line + InternalError, //! internal process error, or over the pass judge line + OverPassJudge, //! over the pass judge lines StuckStop, //! detected stuck vehicle YieldStuckStop, //! detected yield stuck vehicle NonOccludedCollisionStop, //! detected collision while FOV is clear @@ -162,41 +167,7 @@ using DecisionResult = std::variant< FullyPrioritized //! only detect vehicles violating traffic rules >; -inline std::string formatDecisionResult(const DecisionResult & decision_result) -{ - if (std::holds_alternative(decision_result)) { - const auto indecisive = std::get(decision_result); - return "Indecisive because " + indecisive.error; - } - if (std::holds_alternative(decision_result)) { - return "StuckStop"; - } - if (std::holds_alternative(decision_result)) { - return "YieldStuckStop"; - } - if (std::holds_alternative(decision_result)) { - return "NonOccludedCollisionStop"; - } - if (std::holds_alternative(decision_result)) { - return "FirstWaitBeforeOcclusion"; - } - if (std::holds_alternative(decision_result)) { - return "PeekingTowardOcclusion"; - } - if (std::holds_alternative(decision_result)) { - return "OccludedCollisionStop"; - } - if (std::holds_alternative(decision_result)) { - return "OccludedAbsenceTrafficLight"; - } - if (std::holds_alternative(decision_result)) { - return "Safe"; - } - if (std::holds_alternative(decision_result)) { - return "FullyPrioritized"; - } - return ""; -} +std::string formatDecisionResult(const DecisionResult & decision_result); } // namespace behavior_velocity_planner::intersection diff --git a/planning/behavior_velocity_intersection_module/src/interpolated_path_info.hpp b/planning/behavior_velocity_intersection_module/src/interpolated_path_info.hpp index c47f016fbdbda..9002c88354d68 100644 --- a/planning/behavior_velocity_intersection_module/src/interpolated_path_info.hpp +++ b/planning/behavior_velocity_intersection_module/src/interpolated_path_info.hpp @@ -27,7 +27,6 @@ namespace behavior_velocity_planner::intersection { /** - * @struct * @brief wrapper class of interpolated path with lane id */ struct InterpolatedPathInfo diff --git a/planning/behavior_velocity_intersection_module/src/intersection_lanelets.hpp b/planning/behavior_velocity_intersection_module/src/intersection_lanelets.hpp index 11deae6bdc001..9624d375de122 100644 --- a/planning/behavior_velocity_intersection_module/src/intersection_lanelets.hpp +++ b/planning/behavior_velocity_intersection_module/src/intersection_lanelets.hpp @@ -31,7 +31,6 @@ namespace behavior_velocity_planner::intersection { /** - * @struct * @brief see the document for more details of IntersectionLanelets */ struct IntersectionLanelets @@ -174,7 +173,6 @@ struct IntersectionLanelets }; /** - * @struct * @brief see the document for more details of PathLanelets */ struct PathLanelets diff --git a/planning/behavior_velocity_intersection_module/src/intersection_stoplines.hpp b/planning/behavior_velocity_intersection_module/src/intersection_stoplines.hpp index 64d20b81e3fad..99d79d4468b38 100644 --- a/planning/behavior_velocity_intersection_module/src/intersection_stoplines.hpp +++ b/planning/behavior_velocity_intersection_module/src/intersection_stoplines.hpp @@ -21,7 +21,6 @@ namespace behavior_velocity_planner::intersection { /** - * @struct * @brief see the document for more details of IntersectionStopLines */ struct IntersectionStopLines @@ -63,9 +62,9 @@ struct IntersectionStopLines /** * second_pass_judge_line is before second_attention_stopline by the braking distance. if - * second_attention_lane is null, it is same as first_pass_judge_line + * second_attention_lane is null, it is null */ - size_t second_pass_judge_line{0}; + std::optional second_pass_judge_line{std::nullopt}; /** * occlusion_wo_tl_pass_judge_line is null if ego footprint along the path does not intersect with diff --git a/planning/behavior_velocity_intersection_module/src/manager.cpp b/planning/behavior_velocity_intersection_module/src/manager.cpp index 615991bc5e027..8ab67c810a30e 100644 --- a/planning/behavior_velocity_intersection_module/src/manager.cpp +++ b/planning/behavior_velocity_intersection_module/src/manager.cpp @@ -133,6 +133,11 @@ IntersectionModuleManager::IntersectionModuleManager(rclcpp::Node & node) ip.collision_detection.ignore_on_red_traffic_light.object_margin_to_path = getOrDeclareParameter( node, ns + ".collision_detection.ignore_on_red_traffic_light.object_margin_to_path"); + ip.collision_detection.avoid_collision_by_acceleration + .object_time_margin_to_collision_point = getOrDeclareParameter( + node, + ns + + ".collision_detection.avoid_collision_by_acceleration.object_time_margin_to_collision_point"); ip.occlusion.enable = getOrDeclareParameter(node, ns + ".occlusion.enable"); ip.occlusion.occlusion_attention_area_length = diff --git a/planning/behavior_velocity_intersection_module/src/object_manager.cpp b/planning/behavior_velocity_intersection_module/src/object_manager.cpp new file mode 100644 index 0000000000000..ea5d89fe8052d --- /dev/null +++ b/planning/behavior_velocity_intersection_module/src/object_manager.cpp @@ -0,0 +1,309 @@ +// 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. + +#include "object_manager.hpp" + +#include +#include +#include // for toPolygon2d + +#include +#include +#include + +#include +#include + +#include + +namespace +{ +std::string to_string(const unique_identifier_msgs::msg::UUID & uuid) +{ + std::stringstream ss; + for (auto i = 0; i < 16; ++i) { + ss << std::hex << std::setfill('0') << std::setw(2) << +uuid.uuid[i]; + } + return ss.str(); +} + +tier4_autoware_utils::Polygon2d createOneStepPolygon( + const geometry_msgs::msg::Pose & prev_pose, const geometry_msgs::msg::Pose & next_pose, + const autoware_auto_perception_msgs::msg::Shape & shape) +{ + namespace bg = boost::geometry; + const auto prev_poly = tier4_autoware_utils::toPolygon2d(prev_pose, shape); + const auto next_poly = tier4_autoware_utils::toPolygon2d(next_pose, shape); + + tier4_autoware_utils::Polygon2d one_step_poly; + for (const auto & point : prev_poly.outer()) { + one_step_poly.outer().push_back(point); + } + for (const auto & point : next_poly.outer()) { + one_step_poly.outer().push_back(point); + } + + bg::correct(one_step_poly); + + tier4_autoware_utils::Polygon2d convex_one_step_poly; + bg::convex_hull(one_step_poly, convex_one_step_poly); + + return convex_one_step_poly; +} + +} // namespace + +namespace behavior_velocity_planner::intersection +{ +namespace bg = boost::geometry; + +ObjectInfo::ObjectInfo(const unique_identifier_msgs::msg::UUID & uuid) : uuid_str(::to_string(uuid)) +{ +} + +void ObjectInfo::initialize( + const autoware_auto_perception_msgs::msg::PredictedObject & object, + std::optional attention_lanelet_opt_, + std::optional stopline_opt_) +{ + predicted_object_ = object; + attention_lanelet_opt = attention_lanelet_opt_; + stopline_opt = stopline_opt_; + unsafe_interval_ = std::nullopt; + calc_dist_to_stopline(); +} + +void ObjectInfo::update_safety( + const std::optional & unsafe_interval, + const std::optional & safe_interval, const bool safe_under_traffic_control) +{ + unsafe_interval_ = unsafe_interval; + safe_interval_ = safe_interval; + safe_under_traffic_control_ = safe_under_traffic_control; +} + +std::optional ObjectInfo::estimated_past_position( + const double past_duration) const +{ + if (!attention_lanelet_opt) { + return std::nullopt; + } + const auto attention_lanelet = attention_lanelet_opt.value(); + const auto current_arc_coords = lanelet::utils::getArcCoordinates( + {attention_lanelet}, predicted_object_.kinematics.initial_pose_with_covariance.pose); + const auto distance = current_arc_coords.distance; + const auto past_length = + current_arc_coords.length - + predicted_object_.kinematics.initial_twist_with_covariance.twist.linear.x * past_duration; + const auto past_point = lanelet::geometry::fromArcCoordinates( + attention_lanelet.centerline2d(), lanelet::ArcCoordinates{past_length, distance}); + geometry_msgs::msg::Point past_position; + past_position.x = past_point.x(); + past_position.y = past_point.y(); + return std::make_optional(past_position); +} + +void ObjectInfo::calc_dist_to_stopline() +{ + if (!stopline_opt || !attention_lanelet_opt) { + return; + } + const auto attention_lanelet = attention_lanelet_opt.value(); + const auto object_arc_coords = lanelet::utils::getArcCoordinates( + {attention_lanelet}, predicted_object_.kinematics.initial_pose_with_covariance.pose); + const auto stopline = stopline_opt.value(); + geometry_msgs::msg::Pose stopline_center; + stopline_center.position.x = (stopline.front().x() + stopline.back().x()) / 2.0; + stopline_center.position.y = (stopline.front().y() + stopline.back().y()) / 2.0; + stopline_center.position.z = (stopline.front().z() + stopline.back().z()) / 2.0; + const auto stopline_arc_coords = + lanelet::utils::getArcCoordinates({attention_lanelet}, stopline_center); + dist_to_stopline_opt = (stopline_arc_coords.length - object_arc_coords.length); +} + +bool ObjectInfo::can_stop_before_stopline(const double brake_deceleration) const +{ + if (!dist_to_stopline_opt) { + return false; + } + const double observed_velocity = + predicted_object_.kinematics.initial_twist_with_covariance.twist.linear.x; + const double dist_to_stopline = dist_to_stopline_opt.value(); + const double braking_distance = + (observed_velocity * observed_velocity) / (2.0 * brake_deceleration); + return dist_to_stopline > braking_distance; +} + +bool ObjectInfo::can_stop_before_ego_lane( + const double brake_deceleration, const double tolerable_overshoot, + lanelet::ConstLanelet ego_lane) const +{ + if (!dist_to_stopline_opt || !stopline_opt || !attention_lanelet_opt) { + return false; + } + const double dist_to_stopline = dist_to_stopline_opt.value(); + const double observed_velocity = + predicted_object_.kinematics.initial_twist_with_covariance.twist.linear.x; + const double braking_distance = + (observed_velocity * observed_velocity) / (2.0 * brake_deceleration); + if (dist_to_stopline > braking_distance) { + return false; + } + const auto attention_lanelet = attention_lanelet_opt.value(); + const auto stopline = stopline_opt.value(); + const auto stopline_p1 = stopline.front(); + const auto stopline_p2 = stopline.back(); + const tier4_autoware_utils::Point2d stopline_mid{ + stopline_p1.x() + stopline_p2.x() / 2.0, (stopline_p1.y() + stopline_p2.y()) / 2.0}; + const auto attention_lane_end = attention_lanelet.centerline().back(); + const tier4_autoware_utils::LineString2d attention_lane_later_part( + {tier4_autoware_utils::Point2d{stopline_mid.x(), stopline_mid.y()}, + tier4_autoware_utils::Point2d{attention_lane_end.x(), attention_lane_end.y()}}); + std::vector ego_collision_points; + bg::intersection( + attention_lane_later_part, ego_lane.centerline2d().basicLineString(), ego_collision_points); + if (ego_collision_points.empty()) { + return false; + } + const auto expected_collision_point = ego_collision_points.front(); + // distance from object expected stop position to collision point + const double stopline_to_object = -1.0 * dist_to_stopline + braking_distance; + const double stopline_to_ego_path = std::hypot( + expected_collision_point.x() - stopline_mid.x(), + expected_collision_point.y() - stopline_mid.y()); + const double object_to_ego_path = stopline_to_ego_path - stopline_to_object; + // NOTE: if object_to_ego_path < 0, object passed ego path + return object_to_ego_path > tolerable_overshoot; +} + +bool ObjectInfo::before_stopline_by(const double margin) const +{ + if (!dist_to_stopline_opt) { + return false; + } + const double dist_to_stopline = dist_to_stopline_opt.value(); + return dist_to_stopline < margin; +} + +std::shared_ptr ObjectInfoManager::registerObject( + const unique_identifier_msgs::msg::UUID & uuid, const bool belong_attention_area, + const bool belong_intersection_area, const bool is_parked_vehicle) +{ + if (objects_info_.count(uuid) == 0) { + auto object = std::make_shared(uuid); + objects_info_[uuid] = object; + } + auto object = objects_info_[uuid]; + if (belong_attention_area) { + attention_area_objects_.push_back(object); + } else if (belong_intersection_area) { + intersection_area_objects_.push_back(object); + } + if (is_parked_vehicle) { + parked_objects_.push_back(object); + } + return object; +} + +void ObjectInfoManager::registerExistingObject( + const unique_identifier_msgs::msg::UUID & uuid, const bool belong_attention_area, + const bool belong_intersection_area, const bool is_parked_vehicle, + std::shared_ptr object) +{ + objects_info_[uuid] = object; + if (belong_attention_area) { + attention_area_objects_.push_back(object); + } else if (belong_intersection_area) { + intersection_area_objects_.push_back(object); + } + if (is_parked_vehicle) { + parked_objects_.push_back(object); + } +} + +void ObjectInfoManager::clearObjects() +{ + objects_info_.clear(); + attention_area_objects_.clear(); + intersection_area_objects_.clear(); + parked_objects_.clear(); +}; + +std::vector> ObjectInfoManager::allObjects() +{ + std::vector> all_objects = attention_area_objects_; + all_objects.insert( + all_objects.end(), intersection_area_objects_.begin(), intersection_area_objects_.end()); + all_objects.insert(all_objects.end(), parked_objects_.begin(), parked_objects_.end()); + return all_objects; +} + +std::optional findPassageInterval( + const autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, + const autoware_auto_perception_msgs::msg::Shape & shape, + const lanelet::BasicPolygon2d & ego_lane_poly, + const std::optional & first_attention_lane_opt, + const std::optional & second_attention_lane_opt) +{ + const auto first_itr = std::adjacent_find( + predicted_path.path.cbegin(), predicted_path.path.cend(), [&](const auto & a, const auto & b) { + return bg::intersects(ego_lane_poly, ::createOneStepPolygon(a, b, shape)); + }); + if (first_itr == predicted_path.path.cend()) { + // even the predicted path end does not collide with the beginning of ego_lane_poly + return std::nullopt; + } + const auto last_itr = std::adjacent_find( + predicted_path.path.crbegin(), predicted_path.path.crend(), + [&](const auto & a, const auto & b) { + return bg::intersects(ego_lane_poly, ::createOneStepPolygon(a, b, shape)); + }); + if (last_itr == predicted_path.path.crend()) { + // even the predicted path start does not collide with the end of ego_lane_poly + return std::nullopt; + } + + const size_t enter_idx = static_cast(first_itr - predicted_path.path.begin()); + const double object_enter_time = + static_cast(enter_idx) * rclcpp::Duration(predicted_path.time_step).seconds(); + const size_t exit_idx = std::distance(predicted_path.path.begin(), last_itr.base()) - 1; + const double object_exit_time = + static_cast(exit_idx) * rclcpp::Duration(predicted_path.time_step).seconds(); + const auto lane_position = [&]() { + if (first_attention_lane_opt) { + if (lanelet::geometry::inside( + first_attention_lane_opt.value(), + lanelet::BasicPoint2d(first_itr->position.x, first_itr->position.y))) { + return intersection::CollisionInterval::LanePosition::FIRST; + } + } + if (second_attention_lane_opt) { + if (lanelet::geometry::inside( + second_attention_lane_opt.value(), + lanelet::BasicPoint2d(first_itr->position.x, first_itr->position.y))) { + return intersection::CollisionInterval::LanePosition::SECOND; + } + } + return intersection::CollisionInterval::LanePosition::ELSE; + }(); + + std::vector path; + for (const auto & pose : predicted_path.path) { + path.push_back(pose); + } + return intersection::CollisionInterval{ + lane_position, path, {enter_idx, exit_idx}, {object_enter_time, object_exit_time}}; +} + +} // namespace behavior_velocity_planner::intersection diff --git a/planning/behavior_velocity_intersection_module/src/object_manager.hpp b/planning/behavior_velocity_intersection_module/src/object_manager.hpp new file mode 100644 index 0000000000000..e77849570cda8 --- /dev/null +++ b/planning/behavior_velocity_intersection_module/src/object_manager.hpp @@ -0,0 +1,294 @@ +// 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. + +#ifndef OBJECT_MANAGER_HPP_ +#define OBJECT_MANAGER_HPP_ + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace std +{ +template <> +struct hash +{ + size_t operator()(const unique_identifier_msgs::msg::UUID & uid) const + { + const auto & ids = uid.uuid; + boost::uuids::uuid u = {ids[0], ids[1], ids[2], ids[3], ids[4], ids[5], ids[6], ids[7], + ids[8], ids[9], ids[10], ids[11], ids[12], ids[13], ids[14], ids[15]}; + return boost::hash()(u); + } +}; +} // namespace std + +namespace behavior_velocity_planner::intersection +{ + +/** + * @brief store collision information + */ +struct CollisionInterval +{ + enum LanePosition { + FIRST, + SECOND, + ELSE, + }; + LanePosition lane_position{LanePosition::ELSE}; + + //! original predicted path + std::vector path; + + //! possible collision interval position index on path + std::pair interval_position; + + //! possible collision interval time(without TTC margin) + std::pair interval_time; +}; + +struct CollisionKnowledge +{ + //! the time when the expected collision is judged + rclcpp::Time stamp; + + enum SafeType { + UNSAFE, + SAFE, + SAFE_UNDER_TRAFFIC_CONTROL, + }; + SafeType safe_type{SafeType::UNSAFE}; + + //! if !safe, this has value, and it safe, this maybe null if the predicted path does not + //! intersect with ego path + std::optional interval{std::nullopt}; + + double observed_velocity; +}; + +/** + * @brief store collision information of object on the attention area + */ +class ObjectInfo +{ +public: + explicit ObjectInfo(const unique_identifier_msgs::msg::UUID & uuid); + + const autoware_auto_perception_msgs::msg::PredictedObject & predicted_object() const + { + return predicted_object_; + }; + + std::optional is_unsafe() const + { + if (safe_under_traffic_control_) { + return std::nullopt; + } + if (!unsafe_interval_) { + return std::nullopt; + } + return unsafe_interval_; + } + + bool is_safe_under_traffic_control() const { return safe_under_traffic_control_; } + + /** + * @brief update predicted_object_, attention_lanelet, stopline, dist_to_stopline + */ + void initialize( + const autoware_auto_perception_msgs::msg::PredictedObject & predicted_object, + std::optional attention_lanelet_opt, + std::optional stopline_opt); + + /** + * @brief update unsafe_knowledge + */ + void update_safety( + const std::optional & unsafe_interval_opt, + const std::optional & safe_interval_opt, + const bool safe_under_traffic_control); + + /** + * @brief find the estimated position of the object in the past + */ + std::optional estimated_past_position( + const double past_duration) const; + + /** + * @brief check if object can stop before stopline under the deceleration. return false if + * stopline is null for conservative collision checking + */ + bool can_stop_before_stopline(const double brake_deceleration) const; + + /** + * @brief check if object can stop before stopline within the overshoot margin. return false if + * stopline is null for conservative collision checking + */ + bool can_stop_before_ego_lane( + const double brake_deceleration, const double tolerable_overshoot, + lanelet::ConstLanelet ego_lane) const; + + /** + * @brief check if the object is before the stopline within the specified margin + */ + bool before_stopline_by(const double margin) const; + + void setDecisionAt1stPassJudgeLinePassage(const CollisionKnowledge & knowledge) + { + decision_at_1st_pass_judge_line_passage_ = knowledge; + } + + void setDecisionAt2ndPassJudgeLinePassage(const CollisionKnowledge & knowledge) + { + decision_at_2nd_pass_judge_line_passage_ = knowledge; + } + + const std::optional & unsafe_interval() const { return unsafe_interval_; } + + double observed_velocity() const + { + return predicted_object_.kinematics.initial_twist_with_covariance.twist.linear.x; + } + + const std::optional & decision_at_1st_pass_judge_line_passage() const + { + return decision_at_1st_pass_judge_line_passage_; + } + + const std::optional & decision_at_2nd_pass_judge_line_passage() const + { + return decision_at_2nd_pass_judge_line_passage_; + } + + const std::string uuid_str; + +private: + autoware_auto_perception_msgs::msg::PredictedObject predicted_object_; + + //! null if the object in intersection_area but not in attention_area + std::optional attention_lanelet_opt{std::nullopt}; + + //! null if the object in intersection_area but not in attention_area + std::optional stopline_opt{std::nullopt}; + + //! null if the object in intersection_area but not in attention_area + std::optional dist_to_stopline_opt{std::nullopt}; + + //! store the information if judged as UNSAFE + std::optional unsafe_interval_{std::nullopt}; + + //! store the information if judged as SAFE + std::optional safe_interval_{std::nullopt}; + + //! true if the object is judged as negligible given traffic light color + bool safe_under_traffic_control_{false}; + + std::optional decision_at_1st_pass_judge_line_passage_{std::nullopt}; + std::optional decision_at_2nd_pass_judge_line_passage_{std::nullopt}; + + /** + * @brief calculate/update the distance to corresponding stopline + */ + void calc_dist_to_stopline(); +}; + +/** + * @brief store predicted objects for intersection + */ +class ObjectInfoManager +{ +public: + std::shared_ptr registerObject( + const unique_identifier_msgs::msg::UUID & uuid, const bool belong_attention_area, + const bool belong_intersection_area, const bool is_parked); + + void registerExistingObject( + const unique_identifier_msgs::msg::UUID & uuid, const bool belong_attention_area, + const bool belong_intersection_area, const bool is_parked, + std::shared_ptr object); + + void clearObjects(); + + const std::vector> & attentionObjects() const + { + return attention_area_objects_; + } + + const std::vector> & parkedObjects() const { return parked_objects_; } + + std::vector> allObjects(); + + const std::unordered_map> & + getObjectsMap() + { + return objects_info_; + } + + void setPassed1stPassJudgeLineFirstTime(const rclcpp::Time & time) + { + passed_1st_judge_line_first_time_ = time; + } + void setPassed2ndPassJudgeLineFirstTime(const rclcpp::Time & time) + { + passed_2nd_judge_line_first_time_ = time; + } + +private: + std::unordered_map> objects_info_; + + //! belong to attention area + std::vector> attention_area_objects_; + + //! does not belong to attention area but to intersection area + std::vector> intersection_area_objects_; + + //! parked objects on attention_area/intersection_area + std::vector> parked_objects_; + + std::optional passed_1st_judge_line_first_time_{std::nullopt}; + std::optional passed_2nd_judge_line_first_time_{std::nullopt}; +}; + +/** + * @brief return the CollisionInterval struct if the predicted path collides ego path geometrically + */ +std::optional findPassageInterval( + const autoware_auto_perception_msgs::msg::PredictedPath & predicted_path, + const autoware_auto_perception_msgs::msg::Shape & shape, + const lanelet::BasicPolygon2d & ego_lane_poly, + const std::optional & first_attention_lane_opt, + const std::optional & second_attention_lane_opt); + +} // namespace behavior_velocity_planner::intersection + +#endif // OBJECT_MANAGER_HPP_ diff --git a/planning/behavior_velocity_intersection_module/src/result.hpp b/planning/behavior_velocity_intersection_module/src/result.hpp index cc6ad880b8153..5d82183cee2fb 100644 --- a/planning/behavior_velocity_intersection_module/src/result.hpp +++ b/planning/behavior_velocity_intersection_module/src/result.hpp @@ -15,6 +15,7 @@ #ifndef RESULT_HPP_ #define RESULT_HPP_ +#include #include namespace behavior_velocity_planner::intersection @@ -23,10 +24,6 @@ namespace behavior_velocity_planner::intersection template class Result { -public: - static Result make_ok(const Ok & ok) { return Result(ok); } - static Result make_err(const Error & err) { return Result(err); } - public: explicit Result(const Ok & ok) : data_(ok) {} explicit Result(const Error & err) : data_(err) {} @@ -39,6 +36,18 @@ class Result std::variant data_; }; +template +Result make_ok(Args &&... args) +{ + return Result(Ok{std::forward(args)...}); +} + +template +Result make_err(Args &&... args) +{ + return Result(Error{std::forward(args)...}); +} + } // namespace behavior_velocity_planner::intersection #endif // RESULT_HPP_ diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp b/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp index 90242dc3edd7e..75e2da034780a 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp @@ -40,6 +40,10 @@ namespace behavior_velocity_planner { namespace bg = boost::geometry; +using intersection::make_err; +using intersection::make_ok; +using intersection::Result; + IntersectionModule::IntersectionModule( const int64_t module_id, const int64_t lane_id, [[maybe_unused]] std::shared_ptr planner_data, @@ -95,10 +99,8 @@ bool IntersectionModule::modifyPathVelocity(PathWithLaneId * path, StopReason * debug_data_ = DebugData(); *stop_reason = planning_utils::initializeStopReason(StopReason::INTERSECTION); - // set default RTC initializeRTCStatus(); - // calculate the const auto decision_result = modifyPathVelocityDetail(path, stop_reason); prev_decision_result_ = decision_result; @@ -112,7 +114,6 @@ bool IntersectionModule::modifyPathVelocity(PathWithLaneId * path, StopReason * reactRTCApproval(decision_result, path, stop_reason); - RCLCPP_DEBUG(logger_, "===== plan end ====="); return true; } @@ -141,133 +142,145 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( const auto [interpolated_path_info, intersection_stoplines, path_lanelets] = prepare_data.ok(); const auto & intersection_lanelets = intersection_lanelets_.value(); - const auto closest_idx = intersection_stoplines.closest_idx; - - // utility functions - auto fromEgoDist = [&](const size_t index) { - return motion_utils::calcSignedArcLength(path->points, closest_idx, index); - }; - auto stoppedForDuration = - [&](const size_t pos, const double duration, StateMachine & state_machine) { - const double dist_stopline = fromEgoDist(pos); - const bool approached_dist_stopline = - (std::fabs(dist_stopline) < planner_param_.common.stopline_overshoot_margin); - const bool over_stopline = (dist_stopline < 0.0); - const bool is_stopped_duration = planner_data_->isVehicleStopped(duration); - if (over_stopline) { - state_machine.setState(StateMachine::State::GO); - } else if (is_stopped_duration && approached_dist_stopline) { - state_machine.setState(StateMachine::State::GO); - } - return state_machine.getState() == StateMachine::State::GO; - }; - auto stoppedAtPosition = [&](const size_t pos, const double duration) { - const double dist_stopline = fromEgoDist(pos); - const bool approached_dist_stopline = - (std::fabs(dist_stopline) < planner_param_.common.stopline_overshoot_margin); - const bool over_stopline = (dist_stopline < -planner_param_.common.stopline_overshoot_margin); - const bool is_stopped = planner_data_->isVehicleStopped(duration); - if (over_stopline) { - return true; - } else if (is_stopped && approached_dist_stopline) { - return true; - } - return false; - }; - + // ========================================================================================== + // stuck detection + // // stuck vehicle detection is viable even if attention area is empty // so this needs to be checked before attention area validation + // ========================================================================================== const auto is_stuck_status = isStuckStatus(*path, intersection_stoplines, path_lanelets); if (is_stuck_status) { return is_stuck_status.value(); } + // ========================================================================================== + // basic data validation + // // if attention area is empty, collision/occlusion detection is impossible + // + // if attention area is not null but default stop line is not available, ego/backward-path has + // already passed the stop line, so ego is already in the middle of the intersection, or the + // end of the ego path has just entered the entry of this intersection + // + // occlusion stop line is generated from the intersection of ego footprint along the path with the + // attention area, so if this is null, ego has already passed the intersection, or the end of the + // ego path has just entered the entry of this intersection + // ========================================================================================== if (!intersection_lanelets.first_attention_area()) { - return intersection::Indecisive{"attention area is empty"}; + return intersection::InternalError{"attention area is empty"}; } const auto first_attention_area = intersection_lanelets.first_attention_area().value(); - // if attention area is not null but default stop line is not available, ego/backward-path has - // already passed the stop line const auto default_stopline_idx_opt = intersection_stoplines.default_stopline; if (!default_stopline_idx_opt) { - return intersection::Indecisive{"default stop line is null"}; + return intersection::InternalError{"default stop line is null"}; } const auto default_stopline_idx = default_stopline_idx_opt.value(); - // occlusion stop line is generated from the intersection of ego footprint along the path with the - // attention area, so if this is null, eog has already passed the intersection const auto first_attention_stopline_idx_opt = intersection_stoplines.first_attention_stopline; const auto occlusion_peeking_stopline_idx_opt = intersection_stoplines.occlusion_peeking_stopline; if (!first_attention_stopline_idx_opt || !occlusion_peeking_stopline_idx_opt) { - return intersection::Indecisive{"occlusion stop line is null"}; + return intersection::InternalError{"occlusion stop line is null"}; } const auto first_attention_stopline_idx = first_attention_stopline_idx_opt.value(); const auto occlusion_stopline_idx = occlusion_peeking_stopline_idx_opt.value(); - debug_data_.attention_area = intersection_lanelets.attention_area(); - debug_data_.first_attention_area = intersection_lanelets.first_attention_area(); - debug_data_.second_attention_area = intersection_lanelets.second_attention_area(); - debug_data_.occlusion_attention_area = intersection_lanelets.occlusion_attention_area(); - debug_data_.adjacent_area = intersection_lanelets.adjacent_area(); + // ========================================================================================== + // classify the objects to attention_area/intersection_area and update their position, velocity, + // belonging attention lanelet, distance to corresponding stopline + // ========================================================================================== + updateObjectInfoManagerArea(); + + // ========================================================================================== + // occlusion_status is type of occlusion, + // is_occlusion_cleared_with_margin indicates if occlusion is physically detected + // is_occlusion_state indicates if occlusion is detected. OR occlusion is not detected but RTC for + // intersection_occlusion is disapproved, which means ego is virtually occluded + // + // so is_occlusion_cleared_with_margin should be sent to RTC as module decision + // and is_occlusion_status should be only used to decide ego action + // !is_occlusion_state == !physically_occluded && !externally_occluded, so even if occlusion is + // not detected but not approved, SAFE is not sent. + // ========================================================================================== + const auto [occlusion_status, is_occlusion_cleared_with_margin, is_occlusion_state] = + getOcclusionStatus(traffic_prioritized_level, interpolated_path_info); - // get intersection area - const auto lanelet_map_ptr = planner_data_->route_handler_->getLaneletMapPtr(); - const auto & assigned_lanelet = lanelet_map_ptr->laneletLayer.get(lane_id_); - const auto intersection_area = util::getIntersectionArea(assigned_lanelet, lanelet_map_ptr); - // filter objects - auto target_objects = generateTargetObjects(intersection_lanelets, intersection_area); - const auto is_yield_stuck_status = - isYieldStuckStatus(*path, interpolated_path_info, intersection_stoplines, target_objects); - if (is_yield_stuck_status) { - return is_yield_stuck_status.value(); + const auto + [is_over_1st_pass_judge_line, is_over_2nd_pass_judge_line, safely_passed_1st_judge_line, + safely_passed_2nd_judge_line] = + isOverPassJudgeLinesStatus(*path, is_occlusion_state, intersection_stoplines); + + // ========================================================================================== + // calculate the expected vehicle speed and obtain the spatiotemporal profile of ego to the + // exit of intersection + // ========================================================================================== + tier4_debug_msgs::msg::Float64MultiArrayStamped ego_ttc_time_array; + const auto time_distance_array = + calcIntersectionPassingTime(*path, is_prioritized, intersection_stoplines, &ego_ttc_time_array); + + // ========================================================================================== + // run collision checking for each objects considering traffic light level. Also if ego just + // passed each pass judge line for the first time, save current collision status for late + // diagnosis + // ========================================================================================== + updateObjectInfoManagerCollision( + path_lanelets, time_distance_array, traffic_prioritized_level, safely_passed_1st_judge_line, + safely_passed_2nd_judge_line); + + const auto [has_collision, collision_position, too_late_detect_objects, misjudge_objects] = + detectCollision(is_over_1st_pass_judge_line, is_over_2nd_pass_judge_line); + const std::string safety_diag = + generateDetectionBlameDiagnosis(too_late_detect_objects, misjudge_objects); + if (is_permanent_go_) { + if (has_collision) { + const auto closest_idx = intersection_stoplines.closest_idx; + const std::string evasive_diag = generateEgoRiskEvasiveDiagnosis( + *path, closest_idx, time_distance_array, too_late_detect_objects, misjudge_objects); + return intersection::OverPassJudge{safety_diag, evasive_diag}; + } + return intersection::OverPassJudge{ + "no collision is detected", "ego can safely pass the intersection at this rate"}; } - const auto [occlusion_status, is_occlusion_cleared_with_margin, is_occlusion_state] = - getOcclusionStatus( - traffic_prioritized_level, interpolated_path_info, intersection_lanelets, target_objects); - - // TODO(Mamoru Sobue): this should be called later for safety diagnosis - const auto is_over_pass_judge_lines_status = - isOverPassJudgeLinesStatus(*path, is_occlusion_state, intersection_stoplines); - if (is_over_pass_judge_lines_status) { - return is_over_pass_judge_lines_status.ok(); + const bool collision_on_1st_attention_lane = + has_collision && (collision_position == intersection::CollisionInterval::LanePosition::FIRST); + // ========================================================================================== + // this state is very dangerous because ego is very close/over the boundary of 1st attention lane + // and collision is detected on the 1st lane. Since the 2nd attention lane also exists in this + // case, possible another collision may be expected on the 2nd attention lane too. + // ========================================================================================== + std::string safety_report = safety_diag; + if ( + is_over_1st_pass_judge_line && is_over_2nd_pass_judge_line && + is_over_2nd_pass_judge_line.value() && collision_on_1st_attention_lane) { + safety_report += + "\nego is between the 1st and 2nd pass judge line but collision is expected on the 1st " + "attention lane, which is dangerous."; } - [[maybe_unused]] const auto [is_over_1st_pass_judge_line, is_over_2nd_pass_judge_line] = - is_over_pass_judge_lines_status.err(); - const auto & current_pose = planner_data_->current_odometry->pose; - const bool is_over_default_stopline = - util::isOverTargetIndex(*path, closest_idx, current_pose, default_stopline_idx); + const auto closest_idx = intersection_stoplines.closest_idx; + const bool is_over_default_stopline = util::isOverTargetIndex( + *path, closest_idx, planner_data_->current_odometry->pose, default_stopline_idx); const auto collision_stopline_idx = is_over_default_stopline ? closest_idx : default_stopline_idx; - const auto is_green_pseudo_collision_status = isGreenPseudoCollisionStatus( - *path, collision_stopline_idx, intersection_stoplines, target_objects); + // ========================================================================================== + // pseudo collision detection on green light + // ========================================================================================== + const auto is_green_pseudo_collision_status = + isGreenPseudoCollisionStatus(closest_idx, collision_stopline_idx, intersection_stoplines); if (is_green_pseudo_collision_status) { return is_green_pseudo_collision_status.value(); } - // if ego is waiting for collision detection, the entry time into the intersection is a bit - // delayed for the chattering hold - const bool is_go_out = (activated_ && occlusion_activated_); - const double time_to_restart = - (is_go_out || is_prioritized) - ? 0.0 - : (planner_param_.collision_detection.collision_detection_hold_time - - collision_state_machine_.getDuration()); - - // TODO(Mamoru Sobue): if ego is over 1st/2nd pass judge line and collision is expected at 1st/2nd - // pass judge line respectively, ego should go - const auto second_attention_stopline_idx = intersection_stoplines.second_attention_stopline; - const auto last_intersection_stopline_candidate_idx = - second_attention_stopline_idx ? second_attention_stopline_idx.value() : occlusion_stopline_idx; - tier4_debug_msgs::msg::Float64MultiArrayStamped ego_ttc_time_array; - const auto time_distance_array = calcIntersectionPassingTime( - *path, closest_idx, last_intersection_stopline_candidate_idx, time_to_restart, - &ego_ttc_time_array); + // ========================================================================================== + // yield stuck detection + // ========================================================================================== + const auto is_yield_stuck_status = + isYieldStuckStatus(*path, interpolated_path_info, intersection_stoplines); + if (is_yield_stuck_status) { + auto yield_stuck = is_yield_stuck_status.value(); + yield_stuck.safety_report = safety_report; + return yield_stuck; + } - const bool has_collision = checkCollision( - *path, &target_objects, path_lanelets, closest_idx, last_intersection_stopline_candidate_idx, - time_to_restart, traffic_prioritized_level); collision_state_machine_.setStateWithMarginTime( has_collision ? StateMachine::State::STOP : StateMachine::State::GO, logger_.get_child("collision state_machine"), *clock_); @@ -276,7 +289,8 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( if (is_prioritized) { return intersection::FullyPrioritized{ - has_collision_with_margin, closest_idx, collision_stopline_idx, occlusion_stopline_idx}; + has_collision_with_margin, closest_idx, collision_stopline_idx, occlusion_stopline_idx, + safety_report}; } // Safe @@ -286,18 +300,51 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( // Only collision if (!is_occlusion_state && has_collision_with_margin) { return intersection::NonOccludedCollisionStop{ - closest_idx, collision_stopline_idx, occlusion_stopline_idx}; + closest_idx, collision_stopline_idx, occlusion_stopline_idx, safety_report}; } // Occluded - // occlusion_status is assured to be not NOT_OCCLUDED + // utility functions + auto fromEgoDist = [&](const size_t index) { + return motion_utils::calcSignedArcLength(path->points, closest_idx, index); + }; + auto stoppedForDuration = + [&](const size_t pos, const double duration, StateMachine & state_machine) { + const double dist_stopline = fromEgoDist(pos); + const bool approached_dist_stopline = + (std::fabs(dist_stopline) < planner_param_.common.stopline_overshoot_margin); + const bool over_stopline = (dist_stopline < 0.0); + const bool is_stopped_duration = planner_data_->isVehicleStopped(duration); + if (over_stopline) { + state_machine.setState(StateMachine::State::GO); + } else if (is_stopped_duration && approached_dist_stopline) { + state_machine.setState(StateMachine::State::GO); + } + return state_machine.getState() == StateMachine::State::GO; + }; + auto stoppedAtPosition = [&](const size_t pos, const double duration) { + const double dist_stopline = fromEgoDist(pos); + const bool approached_dist_stopline = + (std::fabs(dist_stopline) < planner_param_.common.stopline_overshoot_margin); + const bool over_stopline = (dist_stopline < -planner_param_.common.stopline_overshoot_margin); + const bool is_stopped = planner_data_->isVehicleStopped(duration); + if (over_stopline) { + return true; + } else if (is_stopped && approached_dist_stopline) { + return true; + } + return false; + }; + const auto occlusion_wo_tl_pass_judge_line_idx = intersection_stoplines.occlusion_wo_tl_pass_judge_line; const bool stopped_at_default_line = stoppedForDuration( default_stopline_idx, planner_param_.occlusion.temporal_stop_time_before_peeking, before_creep_state_machine_); if (stopped_at_default_line) { + // ========================================================================================== // if specified the parameter occlusion.temporal_stop_before_attention_area OR // has_no_traffic_light_, ego will temporarily stop before entering attention area + // ========================================================================================== const bool temporal_stop_before_attention_required = (planner_param_.occlusion.temporal_stop_before_attention_area || !has_traffic_light_) ? !stoppedForDuration( @@ -307,7 +354,7 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( : false; if (!has_traffic_light_) { if (fromEgoDist(occlusion_wo_tl_pass_judge_line_idx) < 0) { - return intersection::Indecisive{ + return intersection::InternalError{ "already passed maximum peeking line in the absence of traffic light"}; } return intersection::OccludedAbsenceTrafficLight{ @@ -316,10 +363,15 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( temporal_stop_before_attention_required, closest_idx, first_attention_stopline_idx, - occlusion_wo_tl_pass_judge_line_idx}; + occlusion_wo_tl_pass_judge_line_idx, + safety_report}; } + + // ========================================================================================== // following remaining block is "has_traffic_light_" + // // if ego is stuck by static occlusion in the presence of traffic light, start timeout count + // ========================================================================================== const bool is_static_occlusion = occlusion_status == OcclusionType::STATICALLY_OCCLUDED; const bool is_stuck_by_static_occlusion = stoppedAtPosition( @@ -355,7 +407,8 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( collision_stopline_idx, first_attention_stopline_idx, occlusion_stopline_idx, - static_occlusion_timeout}; + static_occlusion_timeout, + safety_report}; } else { return intersection::PeekingTowardOcclusion{ is_occlusion_cleared_with_margin, @@ -398,7 +451,17 @@ void prepareRTCByDecisionResult( template <> void prepareRTCByDecisionResult( - [[maybe_unused]] const intersection::Indecisive & result, + [[maybe_unused]] const intersection::InternalError & result, + [[maybe_unused]] const autoware_auto_planning_msgs::msg::PathWithLaneId & path, + [[maybe_unused]] bool * default_safety, [[maybe_unused]] double * default_distance, + [[maybe_unused]] bool * occlusion_safety, [[maybe_unused]] double * occlusion_distance) +{ + return; +} + +template <> +void prepareRTCByDecisionResult( + [[maybe_unused]] const intersection::OverPassJudge & result, [[maybe_unused]] const autoware_auto_planning_msgs::msg::PathWithLaneId & path, [[maybe_unused]] bool * default_safety, [[maybe_unused]] double * default_distance, [[maybe_unused]] bool * occlusion_safety, [[maybe_unused]] double * occlusion_distance) @@ -606,7 +669,22 @@ template <> void reactRTCApprovalByDecisionResult( [[maybe_unused]] const bool rtc_default_approved, [[maybe_unused]] const bool rtc_occlusion_approved, - [[maybe_unused]] const intersection::Indecisive & decision_result, + [[maybe_unused]] const intersection::InternalError & decision_result, + [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, + [[maybe_unused]] const double baselink2front, + [[maybe_unused]] autoware_auto_planning_msgs::msg::PathWithLaneId * path, + [[maybe_unused]] StopReason * stop_reason, + [[maybe_unused]] VelocityFactorInterface * velocity_factor, + [[maybe_unused]] IntersectionModule::DebugData * debug_data) +{ + return; +} + +template <> +void reactRTCApprovalByDecisionResult( + [[maybe_unused]] const bool rtc_default_approved, + [[maybe_unused]] const bool rtc_occlusion_approved, + [[maybe_unused]] const intersection::OverPassJudge & decision_result, [[maybe_unused]] const IntersectionModule::PlannerParam & planner_param, [[maybe_unused]] const double baselink2front, [[maybe_unused]] autoware_auto_planning_msgs::msg::PathWithLaneId * path, @@ -640,7 +718,7 @@ void reactRTCApprovalByDecisionResult( { tier4_planning_msgs::msg::StopFactor stop_factor; stop_factor.stop_pose = path->points.at(stopline_idx).point.pose; - stop_factor.stop_factor_points = planning_utils::toRosPoints(debug_data->conflicting_targets); + stop_factor.stop_factor_points = planning_utils::toRosPoints(debug_data->unsafe_targets); planning_utils::appendStopReason(stop_factor, stop_reason); velocity_factor->set( path->points, path->points.at(closest_idx).point.pose, @@ -689,7 +767,7 @@ void reactRTCApprovalByDecisionResult( { tier4_planning_msgs::msg::StopFactor stop_factor; stop_factor.stop_pose = path->points.at(stopline_idx).point.pose; - stop_factor.stop_factor_points = planning_utils::toRosPoints(debug_data->conflicting_targets); + stop_factor.stop_factor_points = planning_utils::toRosPoints(debug_data->unsafe_targets); planning_utils::appendStopReason(stop_factor, stop_reason); velocity_factor->set( path->points, path->points.at(closest_idx).point.pose, @@ -807,7 +885,6 @@ void reactRTCApprovalByDecisionResult( "PeekingTowardOcclusion, approval = (default: %d, occlusion: %d)", rtc_default_approved, rtc_occlusion_approved); // NOTE: creep_velocity should be inserted first at closest_idx if !rtc_default_approved - if (!rtc_occlusion_approved && planner_param.occlusion.enable) { const size_t occlusion_peeking_stopline = decision_result.temporal_stop_before_attention_required @@ -1125,84 +1202,7 @@ IntersectionModule::TrafficPrioritizedLevel IntersectionModule::getTrafficPriori return TrafficPrioritizedLevel::NOT_PRIORITIZED; } -TargetObjects IntersectionModule::generateTargetObjects( - const intersection::IntersectionLanelets & intersection_lanelets, - const std::optional & intersection_area) const -{ - const auto & objects_ptr = planner_data_->predicted_objects; - // extract target objects - TargetObjects target_objects; - target_objects.header = objects_ptr->header; - const auto & attention_lanelets = intersection_lanelets.attention(); - const auto & attention_lanelet_stoplines = intersection_lanelets.attention_stoplines(); - const auto & adjacent_lanelets = intersection_lanelets.adjacent(); - for (const auto & object : objects_ptr->objects) { - // ignore non-vehicle type objects, such as pedestrian. - if (!isTargetCollisionVehicleType(object)) { - continue; - } - - // check direction of objects - const auto object_direction = util::getObjectPoseWithVelocityDirection(object.kinematics); - const auto belong_adjacent_lanelet_id = - checkAngleForTargetLanelets(object_direction, adjacent_lanelets, false); - if (belong_adjacent_lanelet_id) { - continue; - } - - const auto is_parked_vehicle = - std::fabs(object.kinematics.initial_twist_with_covariance.twist.linear.x) < - planner_param_.occlusion.ignore_parked_vehicle_speed_threshold; - auto & container = is_parked_vehicle ? target_objects.parked_attention_objects - : target_objects.attention_objects; - if (intersection_area) { - const auto & obj_pos = object.kinematics.initial_pose_with_covariance.pose.position; - const auto obj_poly = tier4_autoware_utils::toPolygon2d(object); - const auto intersection_area_2d = intersection_area.value(); - const auto belong_attention_lanelet_id = - checkAngleForTargetLanelets(object_direction, attention_lanelets, is_parked_vehicle); - if (belong_attention_lanelet_id) { - const auto id = belong_attention_lanelet_id.value(); - TargetObject target_object; - target_object.object = object; - target_object.attention_lanelet = attention_lanelets.at(id); - target_object.stopline = attention_lanelet_stoplines.at(id); - container.push_back(target_object); - } else if (bg::within(Point2d{obj_pos.x, obj_pos.y}, intersection_area_2d)) { - TargetObject target_object; - target_object.object = object; - target_object.attention_lanelet = std::nullopt; - target_object.stopline = std::nullopt; - target_objects.intersection_area_objects.push_back(target_object); - } - } else if (const auto belong_attention_lanelet_id = checkAngleForTargetLanelets( - object_direction, attention_lanelets, is_parked_vehicle); - belong_attention_lanelet_id.has_value()) { - // intersection_area is not available, use detection_area_with_margin as before - const auto id = belong_attention_lanelet_id.value(); - TargetObject target_object; - target_object.object = object; - target_object.attention_lanelet = attention_lanelets.at(id); - target_object.stopline = attention_lanelet_stoplines.at(id); - container.push_back(target_object); - } - } - for (const auto & object : target_objects.attention_objects) { - target_objects.all_attention_objects.push_back(object); - } - for (const auto & object : target_objects.parked_attention_objects) { - target_objects.all_attention_objects.push_back(object); - } - for (auto & object : target_objects.all_attention_objects) { - object.calc_dist_to_stopline(); - } - return target_objects; -} - -intersection::Result< - intersection::Indecisive, - std::pair> -IntersectionModule::isOverPassJudgeLinesStatus( +IntersectionModule::PassJudgeStatus IntersectionModule::isOverPassJudgeLinesStatus( const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const bool is_occlusion_state, const intersection::IntersectionStopLines & intersection_stoplines) { @@ -1216,8 +1216,11 @@ IntersectionModule::isOverPassJudgeLinesStatus( const size_t pass_judge_line_idx = [&]() { if (planner_param_.occlusion.enable) { if (has_traffic_light_) { + // ========================================================================================== // if ego passed the first_pass_judge_line while it is peeking to occlusion, then its - // position is occlusion_stopline_idx. Otherwise it is first_pass_judge_line + // position is changed to occlusion_stopline_idx. even if occlusion is cleared by peeking, + // its position should be occlusion_stopline_idx as before + // ========================================================================================== if (passed_1st_judge_line_while_peeking_) { return occlusion_stopline_idx; } @@ -1226,16 +1229,22 @@ IntersectionModule::isOverPassJudgeLinesStatus( if (is_occlusion_state && is_over_first_pass_judge_line) { passed_1st_judge_line_while_peeking_ = true; return occlusion_stopline_idx; - } else { - return first_pass_judge_line_idx; } + // ========================================================================================== + // Otherwise it is first_pass_judge_line + // ========================================================================================== + return first_pass_judge_line_idx; } else if (is_occlusion_state) { + // ========================================================================================== // if there is no traffic light and occlusion is detected, pass_judge position is beyond // the boundary of first attention area + // ========================================================================================== return occlusion_wo_tl_pass_judge_line_idx; } else { + // ========================================================================================== // if there is no traffic light and occlusion is not detected, pass_judge position is - // default + // default position + // ========================================================================================== return first_pass_judge_line_idx; } } @@ -1246,147 +1255,67 @@ IntersectionModule::isOverPassJudgeLinesStatus( const bool is_over_1st_pass_judge_line = util::isOverTargetIndex(path, closest_idx, current_pose, pass_judge_line_idx); + bool safely_passed_1st_judge_line_first_time = false; if (is_over_1st_pass_judge_line && was_safe && !safely_passed_1st_judge_line_time_) { - safely_passed_1st_judge_line_time_ = clock_->now(); + safely_passed_1st_judge_line_time_ = std::make_pair(clock_->now(), current_pose); + safely_passed_1st_judge_line_first_time = true; } const double baselink2front = planner_data_->vehicle_info_.max_longitudinal_offset_m; debug_data_.first_pass_judge_wall_pose = planning_utils::getAheadPose(pass_judge_line_idx, baselink2front, path); debug_data_.passed_first_pass_judge = safely_passed_1st_judge_line_time_.has_value(); - const auto second_pass_judge_line_idx = intersection_stoplines.second_pass_judge_line; - const bool is_over_2nd_pass_judge_line = - util::isOverTargetIndex(path, closest_idx, current_pose, second_pass_judge_line_idx); - if (is_over_2nd_pass_judge_line && was_safe && !safely_passed_2nd_judge_line_time_) { - safely_passed_2nd_judge_line_time_ = clock_->now(); + const auto second_pass_judge_line_idx_opt = intersection_stoplines.second_pass_judge_line; + const std::optional is_over_2nd_pass_judge_line = + second_pass_judge_line_idx_opt + ? std::make_optional(util::isOverTargetIndex( + path, closest_idx, current_pose, second_pass_judge_line_idx_opt.value())) + : std::nullopt; + bool safely_passed_2nd_judge_line_first_time = false; + if ( + is_over_2nd_pass_judge_line && is_over_2nd_pass_judge_line.value() && was_safe && + !safely_passed_2nd_judge_line_time_) { + safely_passed_2nd_judge_line_time_ = std::make_pair(clock_->now(), current_pose); + safely_passed_2nd_judge_line_first_time = true; + } + if (second_pass_judge_line_idx_opt) { + debug_data_.second_pass_judge_wall_pose = + planning_utils::getAheadPose(second_pass_judge_line_idx_opt.value(), baselink2front, path); } - debug_data_.second_pass_judge_wall_pose = - planning_utils::getAheadPose(second_pass_judge_line_idx, baselink2front, path); debug_data_.passed_second_pass_judge = safely_passed_2nd_judge_line_time_.has_value(); const bool is_over_default_stopline = util::isOverTargetIndex(path, closest_idx, current_pose, default_stopline_idx); + + const bool over_default_stopline_for_pass_judge = + is_over_default_stopline || planner_param_.common.enable_pass_judge_before_default_stopline; + const bool over_pass_judge_line_overall = + is_over_2nd_pass_judge_line ? is_over_2nd_pass_judge_line.value() : is_over_1st_pass_judge_line; if ( - ((is_over_default_stopline || - planner_param_.common.enable_pass_judge_before_default_stopline) && - is_over_2nd_pass_judge_line && was_safe) || + (over_default_stopline_for_pass_judge && over_pass_judge_line_overall && was_safe) || is_permanent_go_) { - /* - * This body is active if ego is - * - over the default stopline AND - * - over the 1st && 2nd pass judge line AND - * - previously safe - * , - * which means ego can stop even if it is over the 1st pass judge line but - * - before default stopline OR - * - before the 2nd pass judge line OR - * - or previously unsafe - * . - * In order for ego to continue peeking or collision detection when occlusion is detected after - * ego passed the 1st pass judge line, it needs to be - * - before the default stopline OR - * - before the 2nd pass judge line OR - * - previously unsafe - */ + // ========================================================================================== + // this body is active if ego is + // - over the default stopline AND + // - over the 1st && 2nd pass judge line AND + // - previously safe + // , + // which means ego can stop even if it is over the 1st pass judge line but + // - before default stopline OR + // - before the 2nd pass judge line OR + // - or previously unsafe + // . + // + // in order for ego to continue peeking or collision detection when occlusion is detected + // after ego passed the 1st pass judge line, it needs to be + // - before the default stopline OR + // - before the 2nd pass judge line OR + // - previously unsafe + // ========================================================================================== is_permanent_go_ = true; - return intersection::Result>::make_ok( - intersection::Indecisive{"over the pass judge line. no plan needed"}); - } - return intersection::Result>::make_err( - std::make_pair(is_over_1st_pass_judge_line, is_over_2nd_pass_judge_line)); -} - -void TargetObject::calc_dist_to_stopline() -{ - if (!attention_lanelet || !stopline) { - return; } - const auto attention_lanelet_val = attention_lanelet.value(); - const auto object_arc_coords = lanelet::utils::getArcCoordinates( - {attention_lanelet_val}, object.kinematics.initial_pose_with_covariance.pose); - const auto stopline_val = stopline.value(); - geometry_msgs::msg::Pose stopline_center; - stopline_center.position.x = (stopline_val.front().x() + stopline_val.back().x()) / 2.0; - stopline_center.position.y = (stopline_val.front().y() + stopline_val.back().y()) / 2.0; - stopline_center.position.z = (stopline_val.front().z() + stopline_val.back().z()) / 2.0; - const auto stopline_arc_coords = - lanelet::utils::getArcCoordinates({attention_lanelet_val}, stopline_center); - dist_to_stopline = (stopline_arc_coords.length - object_arc_coords.length); + return { + is_over_1st_pass_judge_line, is_over_2nd_pass_judge_line, + safely_passed_1st_judge_line_first_time, safely_passed_2nd_judge_line_first_time}; } -/* - bool IntersectionModule::checkFrontVehicleDeceleration( - lanelet::ConstLanelets & ego_lane_with_next_lane, lanelet::ConstLanelet & closest_lanelet, - const Polygon2d & stuck_vehicle_detect_area, - const autoware_auto_perception_msgs::msg::PredictedObject & object, - const double assumed_front_car_decel) - { - const auto & object_pose = object.kinematics.initial_pose_with_covariance.pose; - // consider vehicle in ego-lane && in front of ego - const auto lon_vel = object.kinematics.initial_twist_with_covariance.twist.linear.x; - const double object_decel = - planner_param_.stuck_vehicle.assumed_front_car_decel; // NOTE: this is positive - const double stopping_distance = lon_vel * lon_vel / (2 * object_decel); - - std::vector center_points; - for (auto && p : ego_lane_with_next_lane[0].centerline()) - center_points.push_back(std::move(lanelet::utils::conversion::toGeomMsgPt(p))); - for (auto && p : ego_lane_with_next_lane[1].centerline()) - center_points.push_back(std::move(lanelet::utils::conversion::toGeomMsgPt(p))); - const double lat_offset = - std::fabs(motion_utils::calcLateralOffset(center_points, object_pose.position)); - // get the nearest centerpoint to object - std::vector dist_obj_center_points; - for (const auto & p : center_points) - dist_obj_center_points.push_back(tier4_autoware_utils::calcDistance2d(object_pose.position, - p)); const int obj_closest_centerpoint_idx = std::distance( dist_obj_center_points.begin(), - std::min_element(dist_obj_center_points.begin(), dist_obj_center_points.end())); - // find two center_points whose distances from `closest_centerpoint` cross stopping_distance - double acc_dist_prev = 0.0, acc_dist = 0.0; - auto p1 = center_points[obj_closest_centerpoint_idx]; - auto p2 = center_points[obj_closest_centerpoint_idx]; - for (unsigned i = obj_closest_centerpoint_idx; i < center_points.size() - 1; ++i) { - p1 = center_points[i]; - p2 = center_points[i + 1]; - acc_dist_prev = acc_dist; - const auto arc_position_p1 = - lanelet::utils::getArcCoordinates(ego_lane_with_next_lane, toPose(p1)); - const auto arc_position_p2 = - lanelet::utils::getArcCoordinates(ego_lane_with_next_lane, toPose(p2)); - const double delta = arc_position_p2.length - arc_position_p1.length; - acc_dist += delta; - if (acc_dist > stopping_distance) { - break; - } - } - // if stopping_distance >= center_points, stopping_point is center_points[end] - const double ratio = (acc_dist <= stopping_distance) - ? 0.0 - : (acc_dist - stopping_distance) / (stopping_distance - acc_dist_prev); - // linear interpolation - geometry_msgs::msg::Point stopping_point; - stopping_point.x = (p1.x * ratio + p2.x) / (1 + ratio); - stopping_point.y = (p1.y * ratio + p2.y) / (1 + ratio); - stopping_point.z = (p1.z * ratio + p2.z) / (1 + ratio); - const double lane_yaw = lanelet::utils::getLaneletAngle(closest_lanelet, stopping_point); - stopping_point.x += lat_offset * std::cos(lane_yaw + M_PI / 2.0); - stopping_point.y += lat_offset * std::sin(lane_yaw + M_PI / 2.0); - - // calculate footprint of predicted stopping pose - autoware_auto_perception_msgs::msg::PredictedObject predicted_object = object; - predicted_object.kinematics.initial_pose_with_covariance.pose.position = stopping_point; - predicted_object.kinematics.initial_pose_with_covariance.pose.orientation = - tier4_autoware_utils::createQuaternionFromRPY(0, 0, lane_yaw); - auto predicted_obj_footprint = tier4_autoware_utils::toPolygon2d(predicted_object); - const bool is_in_stuck_area = !bg::disjoint(predicted_obj_footprint, stuck_vehicle_detect_area); - debug_data_.predicted_obj_pose.position = stopping_point; - debug_data_.predicted_obj_pose.orientation = - tier4_autoware_utils::createQuaternionFromRPY(0, 0, lane_yaw); - - if (is_in_stuck_area) { - return true; - } - return false; - } -*/ - } // namespace behavior_velocity_planner diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection.hpp b/planning/behavior_velocity_intersection_module/src/scene_intersection.hpp index 8a34aabe8b918..9527ce8e5ebea 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection.hpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection.hpp @@ -19,6 +19,7 @@ #include "interpolated_path_info.hpp" #include "intersection_lanelets.hpp" #include "intersection_stoplines.hpp" +#include "object_manager.hpp" #include "result.hpp" #include @@ -45,32 +46,6 @@ namespace behavior_velocity_planner { -/** - * @struct - * @brief see the document for more details of IntersectionStopLines - */ -struct TargetObject -{ - autoware_auto_perception_msgs::msg::PredictedObject object; - std::optional attention_lanelet{std::nullopt}; - std::optional stopline{std::nullopt}; - std::optional dist_to_stopline{std::nullopt}; - void calc_dist_to_stopline(); -}; - -/** - * @struct - * @brief categorize TargetObjects - */ -struct TargetObjects -{ - std_msgs::msg::Header header; - std::vector attention_objects; - std::vector parked_attention_objects; - std::vector intersection_area_objects; - std::vector all_attention_objects; // TODO(Mamoru Sobue): avoid copy -}; - class IntersectionModule : public SceneModuleInterface { public: @@ -154,6 +129,10 @@ class IntersectionModule : public SceneModuleInterface { double object_margin_to_path; } ignore_on_red_traffic_light; + struct AvoidCollisionByAcceleration + { + double object_time_margin_to_collision_point; + } avoid_collision_by_acceleration; } collision_detection; struct Occlusion @@ -204,36 +183,37 @@ class IntersectionModule : public SceneModuleInterface std::optional occlusion_stop_wall_pose{std::nullopt}; std::optional occlusion_first_stop_wall_pose{std::nullopt}; std::optional first_pass_judge_wall_pose{std::nullopt}; + std::optional second_pass_judge_wall_pose{std::nullopt}; bool passed_first_pass_judge{false}; bool passed_second_pass_judge{false}; - std::optional second_pass_judge_wall_pose{std::nullopt}; + std::optional absence_traffic_light_creep_wall{std::nullopt}; + std::optional> attention_area{std::nullopt}; std::optional> occlusion_attention_area{std::nullopt}; - std::optional ego_lane{std::nullopt}; std::optional> adjacent_area{std::nullopt}; std::optional first_attention_area{std::nullopt}; std::optional second_attention_area{std::nullopt}; + std::optional ego_lane{std::nullopt}; std::optional stuck_vehicle_detect_area{std::nullopt}; std::optional> yield_stuck_detect_area{std::nullopt}; + std::optional candidate_collision_ego_lane_polygon{std::nullopt}; - std::vector candidate_collision_object_polygons; - autoware_auto_perception_msgs::msg::PredictedObjects conflicting_targets; - autoware_auto_perception_msgs::msg::PredictedObjects amber_ignore_targets; - autoware_auto_perception_msgs::msg::PredictedObjects red_overshoot_ignore_targets; + autoware_auto_perception_msgs::msg::PredictedObjects safe_under_traffic_control_targets; + autoware_auto_perception_msgs::msg::PredictedObjects unsafe_targets; + autoware_auto_perception_msgs::msg::PredictedObjects misjudge_targets; + autoware_auto_perception_msgs::msg::PredictedObjects too_late_detect_targets; autoware_auto_perception_msgs::msg::PredictedObjects stuck_targets; autoware_auto_perception_msgs::msg::PredictedObjects yield_stuck_targets; + autoware_auto_perception_msgs::msg::PredictedObjects parked_targets; std::vector occlusion_polygons; std::optional> nearest_occlusion_projection{std::nullopt}; - autoware_auto_perception_msgs::msg::PredictedObjects blocking_attention_objects; - std::optional absence_traffic_light_creep_wall{std::nullopt}; std::optional static_occlusion_with_traffic_light_timeout{std::nullopt}; }; using TimeDistanceArray = std::vector>; /** - * @struct * @brief categorize traffic light priority */ enum class TrafficPrioritizedLevel { @@ -246,6 +226,41 @@ class IntersectionModule : public SceneModuleInterface }; /** @} */ + /** + * @brief + */ + struct PassJudgeStatus + { + //! true if ego is over the 1st pass judge line + const bool is_over_1st_pass_judge; + + //! true if second_attention_lane exists and ego is over the 2nd pass judge line + const std::optional is_over_2nd_pass_judge; + + //! true only when ego passed 1st pass judge line safely for the first time + const bool safely_passed_1st_judge_line; + + //! true only when ego passed 2nd pass judge line safely for the first time + const bool safely_passed_2nd_judge_line; + }; + + /** + * @brief + */ + struct CollisionStatus + { + enum BlameType { + BLAME_AT_FIRST_PASS_JUDGE, + BLAME_AT_SECOND_PASS_JUDGE, + }; + const bool collision_detected; + const intersection::CollisionInterval::LanePosition collision_position; + const std::vector>> + too_late_detect_objects; + const std::vector>> + misjudge_objects; + }; + IntersectionModule( const int64_t module_id, const int64_t lane_id, std::shared_ptr planner_data, const PlannerParam & planner_param, const std::set & associative_ids, @@ -325,6 +340,9 @@ class IntersectionModule : public SceneModuleInterface //! cache discretized occlusion detection lanelets std::optional> occlusion_attention_divisions_{ std::nullopt}; + + //! save the time when ego observed green traffic light before entering the intersection + std::optional initial_green_light_observed_time_{std::nullopt}; /** @}*/ private: @@ -340,17 +358,19 @@ class IntersectionModule : public SceneModuleInterface bool is_permanent_go_{false}; //! for checking if ego is over the pass judge lines because previously the situation was SAFE - intersection::DecisionResult prev_decision_result_{intersection::Indecisive{""}}; + intersection::DecisionResult prev_decision_result_{intersection::InternalError{""}}; //! flag if ego passed the 1st_pass_judge_line while peeking. If this is true, 1st_pass_judge_line //! is treated as the same position as occlusion_peeking_stopline bool passed_1st_judge_line_while_peeking_{false}; - //! save the time when ego passed the 1st/2nd_pass_judge_line with safe decision. If collision is - //! expected after these variables are non-null, then it is the fault of past perception failure - //! at these time. - std::optional safely_passed_1st_judge_line_time_{std::nullopt}; - std::optional safely_passed_2nd_judge_line_time_{std::nullopt}; + //! save the time and ego position when ego passed the 1st/2nd_pass_judge_line with safe + //! decision. If collision is expected after these variables are non-null, then it is the fault of + //! past perception failure at these time. + std::optional> + safely_passed_1st_judge_line_time_{std::nullopt}; + std::optional> + safely_passed_2nd_judge_line_time_{std::nullopt}; /** @}*/ private: @@ -363,6 +383,9 @@ class IntersectionModule : public SceneModuleInterface */ //! debouncing for stable SAFE decision StateMachine collision_state_machine_; + + //! container for storing safety status of objects on the attention area + intersection::ObjectInfoManager object_info_manager_; /** @} */ private: @@ -388,8 +411,6 @@ class IntersectionModule : public SceneModuleInterface StateMachine static_occlusion_timeout_state_machine_; /** @} */ - std::optional initial_green_light_observed_time_{std::nullopt}; - private: /** *********************************************************** @@ -464,13 +485,13 @@ class IntersectionModule : public SceneModuleInterface /** * @brief prepare basic data structure - * @return return IntersectionStopLines if all data is valid, otherwise Indecisive + * @return return IntersectionStopLines if all data is valid, otherwise InternalError * @note if successful, it is ensure that intersection_lanelets_, * intersection_lanelets.first_conflicting_lane are not null * * To simplify modifyPathVelocityDetail(), this function is used at first */ - intersection::Result prepareIntersectionData( + intersection::Result prepareIntersectionData( const bool is_prioritized, PathWithLaneId * path); /** @@ -518,16 +539,6 @@ class IntersectionModule : public SceneModuleInterface const lanelet::routing::RoutingGraphPtr routing_graph_ptr, const double resolution); /** @} */ -private: - /** - * @defgroup utility [fn] utility member function - * @{ - */ - void stoppedAtPositionForDuration( - const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const size_t position, - const double duration, StateMachine * state_machine); - /** @} */ - private: /** *********************************************************** @@ -547,14 +558,6 @@ class IntersectionModule : public SceneModuleInterface TrafficPrioritizedLevel getTrafficPrioritizedLevel() const; /** @} */ -private: - /** - * @brief categorize target objects - */ - TargetObjects generateTargetObjects( - const intersection::IntersectionLanelets & intersection_lanelets, - const std::optional & intersection_area) const; - private: /** *********************************************************** @@ -598,14 +601,12 @@ class IntersectionModule : public SceneModuleInterface std::optional isYieldStuckStatus( const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const intersection::InterpolatedPathInfo & interpolated_path_info, - const intersection::IntersectionStopLines & intersection_stoplines, - const TargetObjects & target_objects) const; + const intersection::IntersectionStopLines & intersection_stoplines) const; /** * @brief check yield stuck */ bool checkYieldStuckVehicleInIntersection( - const TargetObjects & target_objects, const intersection::InterpolatedPathInfo & interpolated_path_info, const lanelet::ConstLanelets & attention_lanelets) const; /** @} */ @@ -621,27 +622,21 @@ class IntersectionModule : public SceneModuleInterface /** * @brief check occlusion status * @attention this function has access to value() of occlusion_attention_divisions_, - * intersection_lanelets.first_attention_area() + * intersection_lanelets_ intersection_lanelets.first_attention_area() */ std::tuple< OcclusionType, bool /* module detection with margin */, bool /* reconciled occlusion disapproval */> getOcclusionStatus( const TrafficPrioritizedLevel & traffic_prioritized_level, - const intersection::InterpolatedPathInfo & interpolated_path_info, - const intersection::IntersectionLanelets & intersection_lanelets, - const TargetObjects & target_objects); + const intersection::InterpolatedPathInfo & interpolated_path_info); /** * @brief calculate detected occlusion status(NOT | STATICALLY | DYNAMICALLY) + * @attention this function has access to value() of intersection_lanelets_, + * intersection_lanelets.first_attention_area(), occlusion_attention_divisions_ */ - OcclusionType detectOcclusion( - const std::vector & attention_areas, - const lanelet::ConstLanelets & adjacent_lanelets, - const lanelet::CompoundPolygon3d & first_attention_area, - const intersection::InterpolatedPathInfo & interpolated_path_info, - const std::vector & lane_divisions, - const TargetObjects & target_objects); + OcclusionType detectOcclusion(const intersection::InterpolatedPathInfo & interpolated_path_info); /** @} */ private: @@ -654,15 +649,12 @@ class IntersectionModule : public SceneModuleInterface */ /** * @brief check if ego is already over the pass judge line - * @return if ego is over both 1st/2nd pass judge lines, return Indecisive, else return + * @return if ego is over both 1st/2nd pass judge lines, return InternalError, else return * (is_over_1st_pass_judge, is_over_2nd_pass_judge) * @attention this function has access to value() of intersection_stoplines.default_stopline, * intersection_stoplines.occlusion_stopline */ - intersection::Result< - intersection::Indecisive, - std::pair> - isOverPassJudgeLinesStatus( + PassJudgeStatus isOverPassJudgeLinesStatus( const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const bool is_occlusion_state, const intersection::IntersectionStopLines & intersection_stoplines); /** @} */ @@ -678,6 +670,25 @@ class IntersectionModule : public SceneModuleInterface bool isTargetCollisionVehicleType( const autoware_auto_perception_msgs::msg::PredictedObject & object) const; + /** + * @brief find the objects on attention_area/intersection_area and update positional information + * @attention this function has access to value() of intersection_lanelets_ + */ + void updateObjectInfoManagerArea(); + + /** + * @brief find the collision Interval/CollisionKnowledge of registered objects + * @attention this function has access to value() of intersection_lanelets_ + */ + void updateObjectInfoManagerCollision( + const intersection::PathLanelets & path_lanelets, const TimeDistanceArray & time_distance_array, + const TrafficPrioritizedLevel & traffic_prioritized_level, + const bool passed_1st_judge_line_first_time, const bool passed_2nd_judge_line_first_time); + + void cutPredictPathWithinDuration( + const builtin_interfaces::msg::Time & object_stamp, const double time_thr, + autoware_auto_perception_msgs::msg::PredictedPath * predicted_path) const; + /** * @brief check if there are any objects around the stoplines on the attention areas when ego * entered the intersection on green light @@ -687,44 +698,58 @@ class IntersectionModule : public SceneModuleInterface * intersection_stoplines.occlusion_peeking_stopline */ std::optional isGreenPseudoCollisionStatus( - const autoware_auto_planning_msgs::msg::PathWithLaneId & path, - const size_t collision_stopline_idx, - const intersection::IntersectionStopLines & intersection_stoplines, - const TargetObjects & target_objects); + const size_t closest_idx, const size_t collision_stopline_idx, + const intersection::IntersectionStopLines & intersection_stoplines); + + /** + * @brief generate the message explaining why too_late_detect_objects/misjudge_objects exist and + * blame past perception fault + */ + std::string generateDetectionBlameDiagnosis( + const std::vector< + std::pair>> & + too_late_detect_objects, + const std::vector< + std::pair>> & + misjudge_objects) const; /** - * @brief check collision + * @brief generate the message explaining how much ego should accelerate to avoid future dangerous + * situation */ - bool checkCollision( - const autoware_auto_planning_msgs::msg::PathWithLaneId & path, TargetObjects * target_objects, - const intersection::PathLanelets & path_lanelets, const size_t closest_idx, - const size_t last_intersection_stopline_candidate_idx, const double time_delay, - const TrafficPrioritizedLevel & traffic_prioritized_level); + std::string generateEgoRiskEvasiveDiagnosis( + const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const size_t closest_idx, + const TimeDistanceArray & ego_time_distance_array, + const std::vector< + std::pair>> & + too_late_detect_objects, + const std::vector< + std::pair>> & + misjudge_objects) const; + + /** + * @brief return if collision is detected and the collision position + */ + CollisionStatus detectCollision( + const bool is_over_1st_pass_judge_line, const std::optional is_over_2nd_pass_judge_line); std::optional checkAngleForTargetLanelets( const geometry_msgs::msg::Pose & pose, const lanelet::ConstLanelets & target_lanelets, const bool is_parked_vehicle) const; - void cutPredictPathWithDuration(TargetObjects * target_objects, const double time_thr); - /** * @brief calculate ego vehicle profile along the path inside the intersection as the sequence of * (time of arrival, traveled distance) from current ego position + * @attention this function has access to value() of + * intersection_stoplines.occlusion_peeking_stopline, + * intersection_stoplines.first_attention_stopline */ TimeDistanceArray calcIntersectionPassingTime( - const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const size_t closest_idx, - const size_t last_intersection_stopline_candidate_idx, const double time_delay, + const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const bool is_prioritized, + const intersection::IntersectionStopLines & intersection_stoplines, tier4_debug_msgs::msg::Float64MultiArrayStamped * debug_ttc_array); /** @} */ - /* - bool IntersectionModule::checkFrontVehicleDeceleration( - lanelet::ConstLanelets & ego_lane_with_next_lane, lanelet::ConstLanelet & closest_lanelet, - const Polygon2d & stuck_vehicle_detect_area, - const autoware_auto_perception_msgs::msg::PredictedObject & object, - const double assumed_front_car_decel); - */ - mutable DebugData debug_data_; rclcpp::Publisher::SharedPtr decision_state_pub_; rclcpp::Publisher::SharedPtr ego_ttc_pub_; diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp b/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp index 43bb68cf56f67..4f7e8b45d107f 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp @@ -18,42 +18,18 @@ #include // for toGeomPoly #include // for smoothPath #include +#include #include #include // for toPolygon2d #include -#include #include +#include +#include +#include #include -namespace -{ -tier4_autoware_utils::Polygon2d createOneStepPolygon( - const geometry_msgs::msg::Pose & prev_pose, const geometry_msgs::msg::Pose & next_pose, - const autoware_auto_perception_msgs::msg::Shape & shape) -{ - namespace bg = boost::geometry; - const auto prev_poly = tier4_autoware_utils::toPolygon2d(prev_pose, shape); - const auto next_poly = tier4_autoware_utils::toPolygon2d(next_pose, shape); - - tier4_autoware_utils::Polygon2d one_step_poly; - for (const auto & point : prev_poly.outer()) { - one_step_poly.outer().push_back(point); - } - for (const auto & point : next_poly.outer()) { - one_step_poly.outer().push_back(point); - } - - bg::correct(one_step_poly); - - tier4_autoware_utils::Polygon2d convex_one_step_poly; - bg::convex_hull(one_step_poly, convex_one_step_poly); - - return convex_one_step_poly; -} -} // namespace - namespace behavior_velocity_planner { namespace bg = boost::geometry; @@ -79,38 +55,303 @@ bool IntersectionModule::isTargetCollisionVehicleType( return false; } -std::optional -IntersectionModule::isGreenPseudoCollisionStatus( - const autoware_auto_planning_msgs::msg::PathWithLaneId & path, - const size_t collision_stopline_idx, - const intersection::IntersectionStopLines & intersection_stoplines, - const TargetObjects & target_objects) +void IntersectionModule::updateObjectInfoManagerArea() { + const auto & intersection_lanelets = intersection_lanelets_.value(); + const auto & attention_lanelets = intersection_lanelets.attention(); + const auto & attention_lanelet_stoplines = intersection_lanelets.attention_stoplines(); + const auto & adjacent_lanelets = intersection_lanelets.adjacent(); const auto lanelet_map_ptr = planner_data_->route_handler_->getLaneletMapPtr(); const auto & assigned_lanelet = lanelet_map_ptr->laneletLayer.get(lane_id_); - // If there are any vehicles on the attention area when ego entered the intersection on green - // light, do pseudo collision detection because the vehicles are very slow and no collisions may - // be detected. check if ego vehicle entered assigned lanelet - const bool is_green_solid_on = isGreenSolidOn(); - if (!is_green_solid_on) { - return std::nullopt; + const auto intersection_area = util::getIntersectionArea(assigned_lanelet, lanelet_map_ptr); + + // ========================================================================================== + // entries that are not observed in this iteration need to be cleared + // + // NOTE: old_map is not referenced because internal data of object_info_manager is cleared + // ========================================================================================== + const auto old_map = object_info_manager_.getObjectsMap(); + object_info_manager_.clearObjects(); + + for (const auto & predicted_object : planner_data_->predicted_objects->objects) { + if (!isTargetCollisionVehicleType(predicted_object)) { + continue; + } + + // ========================================================================================== + // NOTE: is_parked_vehicle is used because sometimes slow vehicle direction is + // incorrect/reversed/flipped due to tracking. if is_parked_vehicle is true, object direction + // is not checked + // ========================================================================================== + const auto object_direction = + util::getObjectPoseWithVelocityDirection(predicted_object.kinematics); + const auto is_parked_vehicle = + std::fabs(predicted_object.kinematics.initial_twist_with_covariance.twist.linear.x) < + planner_param_.occlusion.ignore_parked_vehicle_speed_threshold; + + const auto belong_adjacent_lanelet_id = + checkAngleForTargetLanelets(object_direction, adjacent_lanelets, false); + if (belong_adjacent_lanelet_id) { + continue; + } + const auto belong_attention_lanelet_id = + checkAngleForTargetLanelets(object_direction, attention_lanelets, is_parked_vehicle); + const auto & obj_pos = predicted_object.kinematics.initial_pose_with_covariance.pose.position; + const bool in_intersection_area = [&]() { + if (!intersection_area) { + return false; + } + return bg::within( + tier4_autoware_utils::Point2d{obj_pos.x, obj_pos.y}, intersection_area.value()); + }(); + std::optional attention_lanelet{std::nullopt}; + std::optional stopline{std::nullopt}; + if (!belong_attention_lanelet_id && !in_intersection_area) { + continue; + } else if (belong_attention_lanelet_id) { + const auto idx = belong_attention_lanelet_id.value(); + attention_lanelet = attention_lanelets.at(idx); + stopline = attention_lanelet_stoplines.at(idx); + } + + const auto object_it = old_map.find(predicted_object.object_id); + if (object_it != old_map.end()) { + auto object_info = object_it->second; + object_info_manager_.registerExistingObject( + predicted_object.object_id, belong_attention_lanelet_id.has_value(), in_intersection_area, + is_parked_vehicle, object_info); + object_info->initialize(predicted_object, attention_lanelet, stopline); + } else { + auto object_info = object_info_manager_.registerObject( + predicted_object.object_id, belong_attention_lanelet_id.has_value(), in_intersection_area, + is_parked_vehicle); + object_info->initialize(predicted_object, attention_lanelet, stopline); + } } - const auto closest_idx = intersection_stoplines.closest_idx; - const auto occlusion_stopline_idx = intersection_stoplines.occlusion_peeking_stopline.value(); - if (!initial_green_light_observed_time_) { - const auto assigned_lane_begin_point = assigned_lanelet.centerline().front(); - const bool approached_assigned_lane = - motion_utils::calcSignedArcLength( - path.points, closest_idx, - tier4_autoware_utils::createPoint( - assigned_lane_begin_point.x(), assigned_lane_begin_point.y(), - assigned_lane_begin_point.z())) < - planner_param_.collision_detection.yield_on_green_traffic_light - .distance_to_assigned_lanelet_start; - if (approached_assigned_lane) { - initial_green_light_observed_time_ = clock_->now(); +} + +void IntersectionModule::updateObjectInfoManagerCollision( + const intersection::PathLanelets & path_lanelets, + const IntersectionModule::TimeDistanceArray & time_distance_array, + const IntersectionModule::TrafficPrioritizedLevel & traffic_prioritized_level, + const bool passed_1st_judge_line_first_time, const bool passed_2nd_judge_line_first_time) +{ + const auto & intersection_lanelets = intersection_lanelets_.value(); + + if (passed_1st_judge_line_first_time) { + object_info_manager_.setPassed1stPassJudgeLineFirstTime(clock_->now()); + } + if (passed_2nd_judge_line_first_time) { + object_info_manager_.setPassed2ndPassJudgeLineFirstTime(clock_->now()); + } + + const double passing_time = time_distance_array.back().first; + const auto & concat_lanelets = path_lanelets.all; + const auto closest_arc_coords = + lanelet::utils::getArcCoordinates(concat_lanelets, planner_data_->current_odometry->pose); + const auto & ego_lane = path_lanelets.ego_or_entry2exit; + debug_data_.ego_lane = ego_lane.polygon3d(); + const auto ego_poly = ego_lane.polygon2d().basicPolygon(); + + // ========================================================================================== + // dynamically change TTC margin according to traffic light color to gradually relax from green to + // red + // ========================================================================================== + const auto [collision_start_margin_time, collision_end_margin_time] = [&]() { + if (traffic_prioritized_level == TrafficPrioritizedLevel::FULLY_PRIORITIZED) { + return std::make_pair( + planner_param_.collision_detection.fully_prioritized.collision_start_margin_time, + planner_param_.collision_detection.fully_prioritized.collision_end_margin_time); + } + if (traffic_prioritized_level == TrafficPrioritizedLevel::PARTIALLY_PRIORITIZED) { + return std::make_pair( + planner_param_.collision_detection.partially_prioritized.collision_start_margin_time, + planner_param_.collision_detection.partially_prioritized.collision_end_margin_time); + } + return std::make_pair( + planner_param_.collision_detection.not_prioritized.collision_start_margin_time, + planner_param_.collision_detection.not_prioritized.collision_end_margin_time); + }(); + + for (auto & object_info : object_info_manager_.attentionObjects()) { + const auto & predicted_object = object_info->predicted_object(); + bool safe_under_traffic_control = false; + if ( + traffic_prioritized_level == TrafficPrioritizedLevel::PARTIALLY_PRIORITIZED && + object_info->can_stop_before_stopline( + planner_param_.collision_detection.ignore_on_amber_traffic_light + .object_expected_deceleration)) { + safe_under_traffic_control = true; + } + if ( + traffic_prioritized_level == TrafficPrioritizedLevel::FULLY_PRIORITIZED && + object_info->can_stop_before_ego_lane( + planner_param_.collision_detection.ignore_on_amber_traffic_light + .object_expected_deceleration, + planner_param_.collision_detection.ignore_on_red_traffic_light.object_margin_to_path, + ego_lane)) { + safe_under_traffic_control = true; + } + + // ========================================================================================== + // check the PredictedPath in the ascending order of its confidence to save the safe/unsafe + // CollisionKnowledge for most probable path + // ========================================================================================== + std::list sorted_predicted_paths; + for (unsigned i = 0; i < predicted_object.kinematics.predicted_paths.size(); ++i) { + sorted_predicted_paths.push_back(&predicted_object.kinematics.predicted_paths.at(i)); + } + sorted_predicted_paths.sort( + [](const auto path1, const auto path2) { return path1->confidence > path2->confidence; }); + + // ========================================================================================== + // if all of the predicted path is lower confidence/geometrically does not intersect with ego + // path, both will be null, which is interpreted as SAFE. if any of the path is "normal", either + // of them has value, not both + // ========================================================================================== + std::optional unsafe_interval{std::nullopt}; + std::optional safe_interval{std::nullopt}; + + for (const auto & predicted_path_ptr : sorted_predicted_paths) { + auto predicted_path = *predicted_path_ptr; + if ( + predicted_path.confidence < + planner_param_.collision_detection.min_predicted_path_confidence) { + continue; + } + cutPredictPathWithinDuration( + planner_data_->predicted_objects->header.stamp, passing_time, &predicted_path); + const auto object_passage_interval_opt = intersection::findPassageInterval( + predicted_path, predicted_object.shape, ego_poly, + intersection_lanelets.first_attention_lane(), + intersection_lanelets.second_attention_lane()); + if (!object_passage_interval_opt) { + // there is no chance of geometric collision for the entire prediction horizon + continue; + } + const auto & object_passage_interval = object_passage_interval_opt.value(); + const auto [object_enter_time, object_exit_time] = object_passage_interval.interval_time; + const auto ego_start_itr = std::lower_bound( + time_distance_array.begin(), time_distance_array.end(), + object_enter_time - collision_start_margin_time, + [](const auto & a, const double b) { return a.first < b; }); + if (ego_start_itr == time_distance_array.end()) { + // ========================================================================================== + // this is the case where at time "object_enter_time - collision_start_margin_time", ego is + // arriving at the exit of the intersection, which means even if we assume that the object + // accelerates and the first collision happens faster by the TTC margin, ego will be already + // arriving at the exist of the intersection. + // ========================================================================================== + continue; + } + auto ego_end_itr = std::lower_bound( + time_distance_array.begin(), time_distance_array.end(), + object_exit_time + collision_end_margin_time, + [](const auto & a, const double b) { return a.first < b; }); + if (ego_end_itr == time_distance_array.end()) { + ego_end_itr = time_distance_array.end() - 1; + } + const double ego_start_arc_length = std::max( + 0.0, closest_arc_coords.length + ego_start_itr->second - + planner_data_->vehicle_info_.rear_overhang_m); + const double ego_end_arc_length = std::min( + closest_arc_coords.length + ego_end_itr->second + + planner_data_->vehicle_info_.max_longitudinal_offset_m, + lanelet::utils::getLaneletLength2d(concat_lanelets)); + const auto trimmed_ego_polygon = lanelet::utils::getPolygonFromArcLength( + concat_lanelets, ego_start_arc_length, ego_end_arc_length); + if (trimmed_ego_polygon.empty()) { + continue; + } + Polygon2d polygon{}; + for (const auto & p : trimmed_ego_polygon) { + polygon.outer().emplace_back(p.x(), p.y()); + } + bg::correct(polygon); + debug_data_.candidate_collision_ego_lane_polygon = toGeomPoly(polygon); + + const auto & object_path = object_passage_interval.path; + const auto [begin, end] = object_passage_interval.interval_position; + bool collision_detected = false; + for (auto i = begin; i <= end; ++i) { + if (bg::intersects( + polygon, + tier4_autoware_utils::toPolygon2d(object_path.at(i), predicted_object.shape))) { + collision_detected = true; + break; + } + } + if (collision_detected) { + // if judged as UNSAFE, return + safe_interval = std::nullopt; + unsafe_interval = object_passage_interval; + break; + } + if (!safe_interval) { + // ========================================================================================== + // save the safe_decision_knowledge for the most probable path. this value is nullified if + // judged UNSAFE during the iteration + // ========================================================================================== + safe_interval = object_passage_interval; + } + } + object_info->update_safety(unsafe_interval, safe_interval, safe_under_traffic_control); + if (passed_1st_judge_line_first_time) { + object_info->setDecisionAt1stPassJudgeLinePassage(intersection::CollisionKnowledge{ + clock_->now(), // stamp + unsafe_interval + ? intersection::CollisionKnowledge::SafeType::UNSAFE + : (safe_under_traffic_control + ? intersection::CollisionKnowledge::SafeType::SAFE_UNDER_TRAFFIC_CONTROL + : intersection::CollisionKnowledge::SafeType::SAFE), // safe + unsafe_interval ? unsafe_interval : safe_interval, // interval + predicted_object.kinematics.initial_twist_with_covariance.twist.linear + .x // observed_velocity + }); + } + if (passed_2nd_judge_line_first_time) { + object_info->setDecisionAt2ndPassJudgeLinePassage(intersection::CollisionKnowledge{ + clock_->now(), // stamp + unsafe_interval + ? intersection::CollisionKnowledge::SafeType::UNSAFE + : (safe_under_traffic_control + ? intersection::CollisionKnowledge::SafeType::SAFE_UNDER_TRAFFIC_CONTROL + : intersection::CollisionKnowledge::SafeType::SAFE), // safe + unsafe_interval ? unsafe_interval : safe_interval, // interval + predicted_object.kinematics.initial_twist_with_covariance.twist.linear + .x // observed_velocity + }); + } + } +} + +void IntersectionModule::cutPredictPathWithinDuration( + const builtin_interfaces::msg::Time & object_stamp, const double time_thr, + autoware_auto_perception_msgs::msg::PredictedPath * path) const +{ + const rclcpp::Time current_time = clock_->now(); + const auto original_path = path->path; + path->path.clear(); + + for (size_t k = 0; k < original_path.size(); ++k) { // each path points + const auto & predicted_pose = original_path.at(k); + const auto predicted_time = + rclcpp::Time(object_stamp) + rclcpp::Duration(path->time_step) * static_cast(k); + if ((predicted_time - current_time).seconds() < time_thr) { + path->path.push_back(predicted_pose); } } +} + +std::optional +IntersectionModule::isGreenPseudoCollisionStatus( + const size_t closest_idx, const size_t collision_stopline_idx, + const intersection::IntersectionStopLines & intersection_stoplines) +{ + // ========================================================================================== + // if there are any vehicles on the attention area when ego entered the intersection on green + // light, do pseudo collision detection because collision is likely to happen. + // ========================================================================================== if (initial_green_light_observed_time_) { const auto now = clock_->now(); const bool still_wait = @@ -119,22 +360,341 @@ IntersectionModule::isGreenPseudoCollisionStatus( if (!still_wait) { return std::nullopt; } + const auto & attention_objects = object_info_manager_.attentionObjects(); const bool exist_close_vehicles = std::any_of( - target_objects.all_attention_objects.begin(), target_objects.all_attention_objects.end(), - [&](const auto & object) { - return object.dist_to_stopline.has_value() && - object.dist_to_stopline.value() < - planner_param_.collision_detection.yield_on_green_traffic_light - .object_dist_to_stopline; + attention_objects.begin(), attention_objects.end(), [&](const auto & object_info) { + return object_info->before_stopline_by( + planner_param_.collision_detection.yield_on_green_traffic_light.object_dist_to_stopline); }); if (exist_close_vehicles) { + const auto occlusion_stopline_idx = intersection_stoplines.occlusion_peeking_stopline.value(); return intersection::NonOccludedCollisionStop{ - closest_idx, collision_stopline_idx, occlusion_stopline_idx}; + closest_idx, collision_stopline_idx, occlusion_stopline_idx, std::string("")}; } } return std::nullopt; } +std::string IntersectionModule::generateDetectionBlameDiagnosis( + const std::vector>> & + too_late_detect_objects, + const std::vector>> & + misjudge_objects) const +{ + std::string diag; + if (!safely_passed_1st_judge_line_time_) { + return diag; + } + const auto [passed_1st_judge_line_time, passed_1st_judge_line_pose] = + safely_passed_1st_judge_line_time_.value(); + const auto passed_1st_judge_line_time_double = + static_cast(passed_1st_judge_line_time.nanoseconds()) / 1e+9; + + const auto now = clock_->now(); + const auto now_double = static_cast(now.nanoseconds()) / 1e+9; + + // CAVEAT: format library causes runtime fault if the # of placeholders is more than the # of + // vargs + for (const auto & [blame_type, object_info] : too_late_detect_objects) { + if ( + blame_type == CollisionStatus::BLAME_AT_FIRST_PASS_JUDGE && object_info->unsafe_interval()) { + const auto & unsafe_interval = object_info->unsafe_interval().value(); + const double time_diff = now_double - passed_1st_judge_line_time_double; + diag += fmt::format( + "object {0} was not detected when ego passed the 1st pass judge line at {1}, but now at " + "{2}, collision is detected after {3}~{4} seconds on the first attention lanelet of type " + "{5}.\n", + object_info->uuid_str, // 0 + passed_1st_judge_line_time_double, // 1 + now_double, // 2 + unsafe_interval.interval_time.first, // 3 + unsafe_interval.interval_time.second, // 4 + magic_enum::enum_name(unsafe_interval.lane_position) // 5 + ); + const auto past_position_opt = object_info->estimated_past_position(time_diff); + if (past_position_opt) { + const auto & past_position = past_position_opt.value(); + diag += fmt::format( + "this object is estimated to have been at x = {0}, y = {1} when ego passed the 1st pass " + "judge line({2} seconds before from now) given the estimated current velocity {3}[m/s]. " + "ego was at x = {4}, y = {5} when it passed the 1st pass judge line so it is the fault " + "of detection side that failed to detect around {6}[m] range at that time.\n", + past_position.x, // 0 + past_position.y, // 1 + time_diff, // 2 + object_info->observed_velocity(), // 3 + passed_1st_judge_line_pose.position.x, // 4 + passed_1st_judge_line_pose.position.y, // 5 + tier4_autoware_utils::calcDistance2d(passed_1st_judge_line_pose, past_position) // 6 + ); + } + } + if ( + safely_passed_2nd_judge_line_time_ && + blame_type == CollisionStatus::BLAME_AT_SECOND_PASS_JUDGE && object_info->unsafe_interval()) { + const auto [passed_2nd_judge_line_time, passed_2nd_judge_line_pose] = + safely_passed_2nd_judge_line_time_.value(); + const auto passed_2nd_judge_line_time_double = + static_cast(passed_2nd_judge_line_time.nanoseconds()) / 1e+9; + + const auto & unsafe_interval = object_info->unsafe_interval().value(); + const double time_diff = now_double - passed_2nd_judge_line_time_double; + diag += fmt::format( + "object {0} was not detected when ego passed the 2nd pass judge line at {1}, but now at " + "{2}, collision is detected after {3}~{4} seconds on the lanelet of type {5}.\n", + object_info->uuid_str, // 0 + passed_2nd_judge_line_time_double, // 1 + now_double, // 2 + unsafe_interval.interval_time.first, // 3 + unsafe_interval.interval_time.second, // 4 + magic_enum::enum_name(unsafe_interval.lane_position) // 5 + ); + const auto past_position_opt = object_info->estimated_past_position(time_diff); + if (past_position_opt) { + const auto & past_position = past_position_opt.value(); + diag += fmt::format( + "this object is estimated to have been at x = {0}, y = {1} when ego passed the 2nd pass " + "judge line({2} seconds before from now) given the estimated current velocity {3}[m/s]. " + "ego was at x = {4}, y = {5} when it passed the 2nd pass judge line so it is the fault " + "of detection side that failed to detect around {6}[m] range at that time.\n", + past_position.x, // 0 + past_position.y, // 1 + time_diff, // 2 + object_info->observed_velocity(), // 3 + passed_2nd_judge_line_pose.position.x, // 4 + passed_2nd_judge_line_pose.position.y, // 5 + tier4_autoware_utils::calcDistance2d(passed_2nd_judge_line_pose, past_position) // 6 + ); + } + } + } + for (const auto & [blame_type, object_info] : misjudge_objects) { + if ( + blame_type == CollisionStatus::BLAME_AT_FIRST_PASS_JUDGE && object_info->unsafe_interval() && + object_info->decision_at_1st_pass_judge_line_passage()) { + const auto & decision_at_1st_pass_judge_line = + object_info->decision_at_1st_pass_judge_line_passage().value(); + const auto decision_at_1st_pass_judge_line_time = + static_cast(decision_at_1st_pass_judge_line.stamp.nanoseconds()) / 1e+9; + const auto & unsafe_interval = object_info->unsafe_interval().value(); + diag += fmt::format( + "object {0} was judged as {1} when ego passed the 1st pass judge line at time {2} " + "previously with the estimated velocity {3}[m/s], but now at {4} collision is detected " + "after {5}~{6} seconds on the first attention lanelet of type {7} with the estimated " + "current velocity {8}[m/s]\n", + object_info->uuid_str, // 0 + magic_enum::enum_name(decision_at_1st_pass_judge_line.safe_type), // 1 + decision_at_1st_pass_judge_line_time, // 2 + decision_at_1st_pass_judge_line.observed_velocity, // 3 + now_double, // 4 + unsafe_interval.interval_time.first, // 5 + unsafe_interval.interval_time.second, // 6 + magic_enum::enum_name(unsafe_interval.lane_position), // 7 + object_info->observed_velocity() // 8 + ); + } + if ( + blame_type == CollisionStatus::BLAME_AT_SECOND_PASS_JUDGE && object_info->unsafe_interval() && + object_info->decision_at_2nd_pass_judge_line_passage()) { + const auto & decision_at_2nd_pass_judge_line = + object_info->decision_at_2nd_pass_judge_line_passage().value(); + const auto decision_at_2nd_pass_judge_line_time = + static_cast(decision_at_2nd_pass_judge_line.stamp.nanoseconds()) / 1e+9; + const auto & unsafe_interval = object_info->unsafe_interval().value(); + diag += fmt::format( + "object {0} was judged as {1} when ego passed the 2nd pass judge line at time {2} " + "previously with the estimated velocity {3}[m/s], but now at {4} collision is detected " + "after {5}~{6} seconds on the lanelet of type {7} with the estimated current velocity " + "{8}[m/s]\n", + object_info->uuid_str, // 0 + magic_enum::enum_name(decision_at_2nd_pass_judge_line.safe_type), // 1 + decision_at_2nd_pass_judge_line_time, // 2 + decision_at_2nd_pass_judge_line.observed_velocity, // 3 + now_double, // 4 + unsafe_interval.interval_time.first, // 5 + unsafe_interval.interval_time.second, // 6 + magic_enum::enum_name(unsafe_interval.lane_position), // 7 + object_info->observed_velocity() // 8 + ); + } + } + return diag; +} + +std::string IntersectionModule::generateEgoRiskEvasiveDiagnosis( + const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const size_t closest_idx, + const IntersectionModule::TimeDistanceArray & ego_time_distance_array, + const std::vector>> & + too_late_detect_objects, + [[maybe_unused]] const std::vector>> & + misjudge_objects) const +{ + static constexpr double min_vel = 1e-2; + std::string diag; + const double ego_vel = planner_data_->current_velocity->twist.linear.x; + for (const auto & [blame_type, object_info] : too_late_detect_objects) { + if (!object_info->unsafe_interval()) { + continue; + } + // object side + const auto & unsafe_interval = object_info->unsafe_interval().value(); + const auto [begin, end] = unsafe_interval.interval_position; + const auto &p1 = unsafe_interval.path.at(begin).position, + p2 = unsafe_interval.path.at(end).position; + const auto collision_pos = + tier4_autoware_utils::createPoint((p1.x + p2.x) / 2, (p1.y + p2.y) / 2, (p1.z + p2.z) / 2); + const auto object_dist_to_margin_point = + tier4_autoware_utils::calcDistance2d( + object_info->predicted_object().kinematics.initial_pose_with_covariance.pose.position, + collision_pos) - + planner_param_.collision_detection.avoid_collision_by_acceleration + .object_time_margin_to_collision_point * + object_info->observed_velocity(); + if (object_dist_to_margin_point <= 0.0) { + continue; + } + const auto object_eta_to_margin_point = + object_dist_to_margin_point / std::max(min_vel, object_info->observed_velocity()); + // ego side + const double ego_dist_to_collision_pos = + motion_utils::calcSignedArcLength(path.points, closest_idx, collision_pos); + const auto ego_eta_to_collision_pos_it = std::lower_bound( + ego_time_distance_array.begin(), ego_time_distance_array.end(), ego_dist_to_collision_pos, + [](const auto & a, const double b) { return a.second < b; }); + if (ego_eta_to_collision_pos_it == ego_time_distance_array.end()) { + continue; + } + const double ego_eta_to_collision_pos = ego_eta_to_collision_pos_it->first; + if (ego_eta_to_collision_pos < object_eta_to_margin_point) { + // this case, ego will pass the collision point before this object get close to the collision + // point within margin just by keeping current plan, so no need to accelerate + continue; + } + diag += fmt::format( + "the object is expected to approach the collision point by the TTC margin in {0} seconds, " + "while ego will arrive there in {1} seconds, so ego needs to accelerate from current " + "velocity {2}[m/s] to {3}[m/s]\n", + object_eta_to_margin_point, // 0 + ego_eta_to_collision_pos, // 1 + ego_vel, // 2 + ego_dist_to_collision_pos / object_eta_to_margin_point // 3 + ); + } + return diag; +} + +IntersectionModule::CollisionStatus IntersectionModule::detectCollision( + const bool is_over_1st_pass_judge_line, const std::optional is_over_2nd_pass_judge_line) +{ + // ========================================================================================== + // if collision is detected for multiple objects, we prioritize collision on the first + // attention lanelet + // ========================================================================================== + bool collision_at_first_lane = false; + bool collision_at_non_first_lane = false; + + // ========================================================================================== + // find the objects which is judges as UNSAFE after ego passed pass judge lines. + // + // misjudge_objects are those that were once judged as safe when ego passed the pass judge line + // + // too_late_detect objects are those that (1) were not detected when ego passed the pass judge + // line (2) were judged as dangerous at the same time when ego passed the pass judge, which are + // expected to have been detected in the prior iteration because ego could have judged as UNSAFE + // in the prior iteration + // ========================================================================================== + std::vector>> + misjudge_objects; + std::vector>> + too_late_detect_objects; + for (const auto & object_info : object_info_manager_.attentionObjects()) { + if (object_info->is_safe_under_traffic_control()) { + debug_data_.safe_under_traffic_control_targets.objects.push_back( + object_info->predicted_object()); + continue; + } + if (!object_info->is_unsafe()) { + continue; + } + const auto & unsafe_info = object_info->is_unsafe().value(); + // ========================================================================================== + // if ego is over the pass judge lines, then the visualization as "too_late_objects" or + // "misjudge_objects" is more important than that for "unsafe" + // + // NOTE: consider a vehicle which was not detected at 1st_pass_judge_passage, and now collision + // detected on the 1st lane, which is "too_late" for 1st lane passage, but once it decelerated + // or yielded, so it turned safe, and ego passed the 2nd pass judge line, but at the same it + // accelerated again, which is "misjudge" for 2nd lane passage. In this case this vehicle is + // visualized as "misjudge" + // ========================================================================================== + auto * debug_container = &debug_data_.unsafe_targets.objects; + if (unsafe_info.lane_position == intersection::CollisionInterval::LanePosition::FIRST) { + collision_at_first_lane = true; + } else { + collision_at_non_first_lane = true; + } + if ( + is_over_1st_pass_judge_line && + unsafe_info.lane_position == intersection::CollisionInterval::LanePosition::FIRST) { + const auto & decision_at_1st_pass_judge_opt = + object_info->decision_at_1st_pass_judge_line_passage(); + if (!decision_at_1st_pass_judge_opt) { + too_late_detect_objects.emplace_back( + CollisionStatus::BlameType::BLAME_AT_FIRST_PASS_JUDGE, object_info); + debug_container = &debug_data_.too_late_detect_targets.objects; + } else { + const auto & decision_at_1st_pass_judge = decision_at_1st_pass_judge_opt.value(); + if ( + decision_at_1st_pass_judge.safe_type != + intersection::CollisionKnowledge::SafeType::UNSAFE) { + misjudge_objects.emplace_back( + CollisionStatus::BlameType::BLAME_AT_FIRST_PASS_JUDGE, object_info); + debug_container = &debug_data_.misjudge_targets.objects; + } else { + too_late_detect_objects.emplace_back( + CollisionStatus::BlameType::BLAME_AT_FIRST_PASS_JUDGE, object_info); + debug_container = &debug_data_.too_late_detect_targets.objects; + } + } + } + if (is_over_2nd_pass_judge_line && is_over_2nd_pass_judge_line.value()) { + const auto & decision_at_2nd_pass_judge_opt = + object_info->decision_at_2nd_pass_judge_line_passage(); + if (!decision_at_2nd_pass_judge_opt) { + too_late_detect_objects.emplace_back( + CollisionStatus::BlameType::BLAME_AT_SECOND_PASS_JUDGE, object_info); + debug_container = &debug_data_.too_late_detect_targets.objects; + } else { + const auto & decision_at_2nd_pass_judge = decision_at_2nd_pass_judge_opt.value(); + if ( + decision_at_2nd_pass_judge.safe_type != + intersection::CollisionKnowledge::SafeType::UNSAFE) { + misjudge_objects.emplace_back( + CollisionStatus::BlameType::BLAME_AT_SECOND_PASS_JUDGE, object_info); + debug_container = &debug_data_.misjudge_targets.objects; + } else { + too_late_detect_objects.emplace_back( + CollisionStatus::BlameType::BLAME_AT_SECOND_PASS_JUDGE, object_info); + debug_container = &debug_data_.too_late_detect_targets.objects; + } + } + } + debug_container->emplace_back(object_info->predicted_object()); + } + if (collision_at_first_lane) { + return { + true, intersection::CollisionInterval::FIRST, too_late_detect_objects, misjudge_objects}; + } else if (collision_at_non_first_lane) { + return {true, intersection::CollisionInterval::ELSE, too_late_detect_objects, misjudge_objects}; + } + return {false, intersection::CollisionInterval::ELSE, too_late_detect_objects, misjudge_objects}; +} + +/* bool IntersectionModule::checkCollision( const autoware_auto_planning_msgs::msg::PathWithLaneId & path, TargetObjects * target_objects, const intersection::PathLanelets & path_lanelets, const size_t closest_idx, @@ -383,6 +943,7 @@ bool IntersectionModule::checkCollision( return collision_detected; } +*/ std::optional IntersectionModule::checkAngleForTargetLanelets( @@ -422,32 +983,9 @@ std::optional IntersectionModule::checkAngleForTargetLanelets( return std::nullopt; } -void IntersectionModule::cutPredictPathWithDuration( - TargetObjects * target_objects, const double time_thr) -{ - const rclcpp::Time current_time = clock_->now(); - for (auto & target_object : target_objects->all_attention_objects) { // each objects - for (auto & predicted_path : - target_object.object.kinematics.predicted_paths) { // each predicted paths - const auto origin_path = predicted_path; - predicted_path.path.clear(); - - for (size_t k = 0; k < origin_path.path.size(); ++k) { // each path points - const auto & predicted_pose = origin_path.path.at(k); - const auto predicted_time = - rclcpp::Time(target_objects->header.stamp) + - rclcpp::Duration(origin_path.time_step) * static_cast(k); - if ((predicted_time - current_time).seconds() < time_thr) { - predicted_path.path.push_back(predicted_pose); - } - } - } - } -} - IntersectionModule::TimeDistanceArray IntersectionModule::calcIntersectionPassingTime( - const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const size_t closest_idx, - const size_t last_intersection_stopline_candidate_idx, const double time_delay, + const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const bool is_prioritized, + const intersection::IntersectionStopLines & intersection_stoplines, tier4_debug_msgs::msg::Float64MultiArrayStamped * debug_ttc_array) { const double intersection_velocity = @@ -460,8 +998,42 @@ IntersectionModule::TimeDistanceArray IntersectionModule::calcIntersectionPassin planner_param_.collision_detection.velocity_profile.minimum_upstream_velocity; const double current_velocity = planner_data_->current_velocity->twist.linear.x; - int assigned_lane_found = false; + // ========================================================================================== + // if ego is waiting for collision detection, the entry time into the intersection + // is a bit delayed for the chattering hold, so we need to "shift" the TimeDistanceArray by + // this delay + // ========================================================================================== + const bool is_go_out = (activated_ && occlusion_activated_); + const double time_delay = (is_go_out || is_prioritized) + ? 0.0 + : (planner_param_.collision_detection.collision_detection_hold_time - + collision_state_machine_.getDuration()); + // ========================================================================================== + // to account for the stopline generated by upstream behavior_velocity modules (like walkway, + // crosswalk), if use_upstream flag is true, the raw velocity of path points after + // last_intersection_stopline_candidate_idx is used, which maybe almost-zero. at those almost-zero + // velocity path points, ego future profile is almost "fixed" there. + // + // last_intersection_stopline_candidate_idx must be carefully decided especially when ego + // velocity is almost zero, because if last_intersection_stopline_candidate_idx is at the + // closest_idx for example, ego is almost "fixed" at current position for the entire + // spatiotemporal profile, which is judged as SAFE because that profile does not collide + // with the predicted paths of objects. + // + // if second_attention_lane exists, second_attention_stopline_idx is used. if not, + // max(occlusion_stopline_idx, first_attention_stopline_idx) is used because + // occlusion_stopline_idx varies depending on the peeking offset parameter + // ========================================================================================== + const auto second_attention_stopline_idx = intersection_stoplines.second_attention_stopline; + const auto occlusion_stopline_idx = intersection_stoplines.occlusion_peeking_stopline.value(); + const auto first_attention_stopline_idx = intersection_stoplines.first_attention_stopline.value(); + const auto closest_idx = intersection_stoplines.closest_idx; + const auto last_intersection_stopline_candidate_idx = + second_attention_stopline_idx ? second_attention_stopline_idx.value() + : std::max(occlusion_stopline_idx, first_attention_stopline_idx); + + int assigned_lane_found = false; // crop intersection part of the path, and set the reference velocity to intersection_velocity // for ego's ttc PathWithLaneId reference_path; diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection_occlusion.cpp b/planning/behavior_velocity_intersection_module/src/scene_intersection_occlusion.cpp index 353826070eff7..b7c2d4c12878c 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection_occlusion.cpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection_occlusion.cpp @@ -34,25 +34,18 @@ std::tuple< bool /* reconciled occlusion disapproval */> IntersectionModule::getOcclusionStatus( const TrafficPrioritizedLevel & traffic_prioritized_level, - const intersection::InterpolatedPathInfo & interpolated_path_info, - const intersection::IntersectionLanelets & intersection_lanelets, - const TargetObjects & target_objects) + const intersection::InterpolatedPathInfo & interpolated_path_info) { - const auto & adjacent_lanelets = intersection_lanelets.adjacent(); + const auto & intersection_lanelets = intersection_lanelets_.value(); const auto & occlusion_attention_lanelets = intersection_lanelets.occlusion_attention(); - const auto & occlusion_attention_area = intersection_lanelets.occlusion_attention_area(); - const auto first_attention_area = intersection_lanelets.first_attention_area().value(); const bool is_amber_or_red = (traffic_prioritized_level == TrafficPrioritizedLevel::PARTIALLY_PRIORITIZED) || (traffic_prioritized_level == TrafficPrioritizedLevel::FULLY_PRIORITIZED); // check occlusion on detection lane - const auto & occlusion_attention_divisions = occlusion_attention_divisions_.value(); auto occlusion_status = (planner_param_.occlusion.enable && !occlusion_attention_lanelets.empty() && !is_amber_or_red) - ? detectOcclusion( - occlusion_attention_area, adjacent_lanelets, first_attention_area, interpolated_path_info, - occlusion_attention_divisions, target_objects) + ? detectOcclusion(interpolated_path_info) : OcclusionType::NOT_OCCLUDED; occlusion_stop_state_machine_.setStateWithMarginTime( occlusion_status == OcclusionType::NOT_OCCLUDED ? StateMachine::State::GO : StateMachine::STOP, @@ -76,13 +69,14 @@ IntersectionModule::getOcclusionStatus( } IntersectionModule::OcclusionType IntersectionModule::detectOcclusion( - const std::vector & attention_areas, - const lanelet::ConstLanelets & adjacent_lanelets, - const lanelet::CompoundPolygon3d & first_attention_area, - const intersection::InterpolatedPathInfo & interpolated_path_info, - const std::vector & lane_divisions, - const TargetObjects & target_objects) + const intersection::InterpolatedPathInfo & interpolated_path_info) { + const auto & intersection_lanelets = intersection_lanelets_.value(); + const auto & adjacent_lanelets = intersection_lanelets.adjacent(); + const auto & attention_areas = intersection_lanelets.occlusion_attention_area(); + const auto first_attention_area = intersection_lanelets.first_attention_area().value(); + const auto & lane_divisions = occlusion_attention_divisions_.value(); + const auto & occ_grid = *planner_data_->occupancy_grid; const auto & current_pose = planner_data_->current_odometry->pose; const double occlusion_dist_thr = planner_param_.occlusion.occlusion_required_clearance_distance; @@ -208,13 +202,15 @@ IntersectionModule::OcclusionType IntersectionModule::detectOcclusion( // re-use attention_mask attention_mask = cv::Mat(width, height, CV_8UC1, cv::Scalar(0)); // (3.1) draw all cells on attention_mask behind blocking vehicles as not occluded - const auto & blocking_attention_objects = target_objects.parked_attention_objects; - for (const auto & blocking_attention_object : blocking_attention_objects) { - debug_data_.blocking_attention_objects.objects.push_back(blocking_attention_object.object); + const auto & blocking_attention_objects = object_info_manager_.parkedObjects(); + for (const auto & blocking_attention_object_info : blocking_attention_objects) { + debug_data_.parked_targets.objects.push_back( + blocking_attention_object_info->predicted_object()); } std::vector> blocking_polygons; - for (const auto & blocking_attention_object : blocking_attention_objects) { - const Polygon2d obj_poly = tier4_autoware_utils::toPolygon2d(blocking_attention_object.object); + for (const auto & blocking_attention_object_info : blocking_attention_objects) { + const Polygon2d obj_poly = + tier4_autoware_utils::toPolygon2d(blocking_attention_object_info->predicted_object()); findCommonCvPolygons(obj_poly.outer(), blocking_polygons); } for (const auto & blocking_polygon : blocking_polygons) { @@ -390,14 +386,9 @@ IntersectionModule::OcclusionType IntersectionModule::detectOcclusion( LineString2d ego_occlusion_line; ego_occlusion_line.emplace_back(current_pose.position.x, current_pose.position.y); ego_occlusion_line.emplace_back(nearest_occlusion_point.point.x, nearest_occlusion_point.point.y); - for (const auto & attention_object : target_objects.all_attention_objects) { - const auto obj_poly = tier4_autoware_utils::toPolygon2d(attention_object.object); - if (bg::intersects(obj_poly, ego_occlusion_line)) { - return OcclusionType::DYNAMICALLY_OCCLUDED; - } - } - for (const auto & attention_object : target_objects.intersection_area_objects) { - const auto obj_poly = tier4_autoware_utils::toPolygon2d(attention_object.object); + for (const auto & attention_object_info : object_info_manager_.allObjects()) { + const auto obj_poly = + tier4_autoware_utils::toPolygon2d(attention_object_info->predicted_object()); if (bg::intersects(obj_poly, ego_occlusion_line)) { return OcclusionType::DYNAMICALLY_OCCLUDED; } diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection_prepare_data.cpp b/planning/behavior_velocity_intersection_module/src/scene_intersection_prepare_data.cpp index 746e615d8c6b0..c44008db9b08b 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection_prepare_data.cpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection_prepare_data.cpp @@ -161,11 +161,13 @@ namespace behavior_velocity_planner { namespace bg = boost::geometry; -intersection::Result +using intersection::make_err; +using intersection::make_ok; +using intersection::Result; + +Result IntersectionModule::prepareIntersectionData(const bool is_prioritized, PathWithLaneId * path) { - using intersection::Result; - const auto lanelet_map_ptr = planner_data_->route_handler_->getLaneletMapPtr(); const auto routing_graph_ptr = planner_data_->route_handler_->getRoutingGraphPtr(); const auto & assigned_lanelet = lanelet_map_ptr->laneletLayer.get(lane_id_); @@ -177,26 +179,32 @@ IntersectionModule::prepareIntersectionData(const bool is_prioritized, PathWithL const auto interpolated_path_info_opt = util::generateInterpolatedPath( lane_id_, associative_ids_, *path, planner_param_.common.path_interpolation_ds, logger_); if (!interpolated_path_info_opt) { - return Result::make_err( - intersection::Indecisive{"splineInterpolate failed"}); + return make_err( + "splineInterpolate failed"); } const auto & interpolated_path_info = interpolated_path_info_opt.value(); if (!interpolated_path_info.lane_id_interval) { - return Result::make_err( - intersection::Indecisive{ - "Path has no interval on intersection lane " + std::to_string(lane_id_)}); + return make_err( + "Path has no interval on intersection lane " + std::to_string(lane_id_)); } - // cache intersection lane information because it is invariant if (!intersection_lanelets_) { intersection_lanelets_ = generateObjectiveLanelets(lanelet_map_ptr, routing_graph_ptr, assigned_lanelet); } auto & intersection_lanelets = intersection_lanelets_.value(); - - // at the very first time of regisTration of this module, the path may not be conflicting with the - // attention area, so update() is called to update the internal data as well as traffic light info + debug_data_.attention_area = intersection_lanelets.attention_area(); + debug_data_.first_attention_area = intersection_lanelets.first_attention_area(); + debug_data_.second_attention_area = intersection_lanelets.second_attention_area(); + debug_data_.occlusion_attention_area = intersection_lanelets.occlusion_attention_area(); + debug_data_.adjacent_area = intersection_lanelets.adjacent_area(); + + // ========================================================================================== + // at the very first time of registration of this module, the path may not be conflicting with + // the attention area, so update() is called to update the internal data as well as traffic + // light info + // ========================================================================================== intersection_lanelets.update( is_prioritized, interpolated_path_info, footprint, baselink2front, routing_graph_ptr); @@ -205,17 +213,17 @@ IntersectionModule::prepareIntersectionData(const bool is_prioritized, PathWithL const auto & first_conflicting_lane_opt = intersection_lanelets.first_conflicting_lane(); if (conflicting_lanelets.empty() || !first_conflicting_area_opt || !first_conflicting_lane_opt) { // this is abnormal - return Result::make_err( - intersection::Indecisive{"conflicting area is empty"}); + return make_err( + "conflicting area is empty"); } const auto & first_conflicting_lane = first_conflicting_lane_opt.value(); const auto & first_conflicting_area = first_conflicting_area_opt.value(); const auto & second_attention_area_opt = intersection_lanelets.second_attention_area(); - // generate all stop line candidates - // see the doc for struct IntersectionStopLines - /// even if the attention area is null, stuck vehicle stop line needs to be generated from - /// conflicting lanes + // ========================================================================================== + // even if the attention area is null, stuck vehicle stop line needs to be generated from + // conflicting lanes, so dummy_first_attention_lane is used + // ========================================================================================== const auto & dummy_first_attention_lane = intersection_lanelets.first_attention_lane() ? intersection_lanelets.first_attention_lane().value() : first_conflicting_lane; @@ -224,8 +232,8 @@ IntersectionModule::prepareIntersectionData(const bool is_prioritized, PathWithL assigned_lanelet, first_conflicting_area, dummy_first_attention_lane, second_attention_area_opt, interpolated_path_info, path); if (!intersection_stoplines_opt) { - return Result::make_err( - intersection::Indecisive{"failed to generate intersection_stoplines"}); + return make_err( + "failed to generate intersection_stoplines"); } const auto & intersection_stoplines = intersection_stoplines_opt.value(); const auto closest_idx = intersection_stoplines.closest_idx; @@ -239,8 +247,8 @@ IntersectionModule::prepareIntersectionData(const bool is_prioritized, PathWithL lanelets_on_path, interpolated_path_info, first_conflicting_area, conflicting_area, first_attention_area_opt, intersection_lanelets.attention_area(), closest_idx); if (!path_lanelets_opt.has_value()) { - return Result::make_err( - intersection::Indecisive{"failed to generate PathLanelets"}); + return make_err( + "failed to generate PathLanelets"); } const auto & path_lanelets = path_lanelets_opt.value(); @@ -250,8 +258,24 @@ IntersectionModule::prepareIntersectionData(const bool is_prioritized, PathWithL planner_data_->occupancy_grid->info.resolution); } - return Result::make_ok( - BasicData{interpolated_path_info, intersection_stoplines, path_lanelets}); + const bool is_green_solid_on = isGreenSolidOn(); + if (is_green_solid_on && !initial_green_light_observed_time_) { + const auto assigned_lane_begin_point = assigned_lanelet.centerline().front(); + const bool approached_assigned_lane = + motion_utils::calcSignedArcLength( + path->points, closest_idx, + tier4_autoware_utils::createPoint( + assigned_lane_begin_point.x(), assigned_lane_begin_point.y(), + assigned_lane_begin_point.z())) < + planner_param_.collision_detection.yield_on_green_traffic_light + .distance_to_assigned_lanelet_start; + if (approached_assigned_lane) { + initial_green_light_observed_time_ = clock_->now(); + } + } + + return make_ok( + interpolated_path_info, intersection_stoplines, path_lanelets); } std::optional IntersectionModule::getStopLineIndexFromMap( @@ -421,8 +445,10 @@ IntersectionModule::generateIntersectionStopLines( int stuck_stopline_ip_int = 0; bool stuck_stopline_valid = true; if (use_stuck_stopline) { + // ========================================================================================== // NOTE: when ego vehicle is approaching attention area and already passed // first_conflicting_area, this could be null. + // ========================================================================================== const auto stuck_stopline_idx_ip_opt = util::getFirstPointInsidePolygonByFootprint( first_conflicting_area, interpolated_path_info, local_footprint, baselink2front); if (!stuck_stopline_idx_ip_opt) { @@ -457,12 +483,13 @@ IntersectionModule::generateIntersectionStopLines( second_attention_stopline_ip_int >= 0 ? static_cast(second_attention_stopline_ip_int) : 0; - // (8) second pass judge line position on interpolated path. It is the same as first pass judge - // line if second_attention_lane is null - int second_pass_judge_ip_int = occlusion_wo_tl_pass_judge_line_ip; - const auto second_pass_judge_line_ip = - second_attention_area_opt ? static_cast(std::max(second_pass_judge_ip_int, 0)) - : first_pass_judge_line_ip; + // (8) second pass judge line position on interpolated path. It is null if second_attention_lane + // is null + size_t second_pass_judge_line_ip = occlusion_wo_tl_pass_judge_line_ip; + bool second_pass_judge_line_valid = false; + if (second_attention_area_opt) { + second_pass_judge_line_valid = true; + } struct IntersectionStopLinesTemp { @@ -528,9 +555,11 @@ IntersectionModule::generateIntersectionStopLines( intersection_stoplines.occlusion_peeking_stopline = intersection_stoplines_temp.occlusion_peeking_stopline; } + if (second_pass_judge_line_valid) { + intersection_stoplines.second_pass_judge_line = + intersection_stoplines_temp.second_pass_judge_line; + } intersection_stoplines.first_pass_judge_line = intersection_stoplines_temp.first_pass_judge_line; - intersection_stoplines.second_pass_judge_line = - intersection_stoplines_temp.second_pass_judge_line; intersection_stoplines.occlusion_wo_tl_pass_judge_line = intersection_stoplines_temp.occlusion_wo_tl_pass_judge_line; return intersection_stoplines; @@ -556,7 +585,7 @@ intersection::IntersectionLanelets IntersectionModule::generateObjectiveLanelets } // for low priority lane - // If ego_lane has right of way (i.e. is high priority), + // if ego_lane has right of way (i.e. is high priority), // ignore yieldLanelets (i.e. low priority lanes) lanelet::ConstLanelets yield_lanelets{}; const auto right_of_ways = assigned_lanelet.regulatoryElementsAs(); diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection_stuck.cpp b/planning/behavior_velocity_intersection_module/src/scene_intersection_stuck.cpp index 7f23bed3c36cd..389c73d651f1e 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection_stuck.cpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection_stuck.cpp @@ -262,21 +262,19 @@ bool IntersectionModule::checkStuckVehicleInIntersection( std::optional IntersectionModule::isYieldStuckStatus( const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const intersection::InterpolatedPathInfo & interpolated_path_info, - const intersection::IntersectionStopLines & intersection_stoplines, - const TargetObjects & target_objects) const + const intersection::IntersectionStopLines & intersection_stoplines) const { const auto closest_idx = intersection_stoplines.closest_idx; auto fromEgoDist = [&](const size_t index) { return motion_utils::calcSignedArcLength(path.points, closest_idx, index); }; - const auto & intersection_lanelets = intersection_lanelets_.value(); // this is OK - const auto default_stopline_idx = intersection_stoplines.default_stopline.value(); // this is OK - const auto first_attention_stopline_idx = - intersection_stoplines.first_attention_stopline.value(); // this is OK + const auto & intersection_lanelets = intersection_lanelets_.value(); + const auto default_stopline_idx = intersection_stoplines.default_stopline.value(); + const auto first_attention_stopline_idx = intersection_stoplines.first_attention_stopline.value(); const auto stuck_stopline_idx_opt = intersection_stoplines.stuck_stopline; const bool yield_stuck_detected = checkYieldStuckVehicleInIntersection( - target_objects, interpolated_path_info, intersection_lanelets.attention_non_preceding()); + interpolated_path_info, intersection_lanelets.attention_non_preceding()); if (yield_stuck_detected) { std::optional stopline_idx = std::nullopt; const bool is_before_default_stopline = fromEgoDist(default_stopline_idx) >= 0.0; @@ -297,14 +295,13 @@ std::optional IntersectionModule::isYieldStuckStat } } if (stopline_idx) { - return intersection::YieldStuckStop{closest_idx, stopline_idx.value()}; + return intersection::YieldStuckStop{closest_idx, stopline_idx.value(), std::string("")}; } } return std::nullopt; } bool IntersectionModule::checkYieldStuckVehicleInIntersection( - const TargetObjects & target_objects, const intersection::InterpolatedPathInfo & interpolated_path_info, const lanelet::ConstLanelets & attention_lanelets) const { @@ -358,19 +355,20 @@ bool IntersectionModule::checkYieldStuckVehicleInIntersection( ::createLaneletFromArcLength(attention_lanelet, yield_stuck_start, yield_stuck_end)); } debug_data_.yield_stuck_detect_area = util::getPolygon3dFromLanelets(yield_stuck_detect_lanelets); - for (const auto & object : target_objects.all_attention_objects) { + for (const auto & object_info : object_info_manager_.attentionObjects()) { + const auto & object = object_info->predicted_object(); const auto obj_v_norm = std::hypot( - object.object.kinematics.initial_twist_with_covariance.twist.linear.x, - object.object.kinematics.initial_twist_with_covariance.twist.linear.y); + object.kinematics.initial_twist_with_covariance.twist.linear.x, + object.kinematics.initial_twist_with_covariance.twist.linear.y); if (obj_v_norm > stuck_vehicle_vel_thr) { continue; } for (const auto & yield_stuck_detect_lanelet : yield_stuck_detect_lanelets) { const bool is_in_lanelet = lanelet::utils::isInLanelet( - object.object.kinematics.initial_pose_with_covariance.pose, yield_stuck_detect_lanelet); + object.kinematics.initial_pose_with_covariance.pose, yield_stuck_detect_lanelet); if (is_in_lanelet) { - debug_data_.yield_stuck_targets.objects.push_back(object.object); + debug_data_.yield_stuck_targets.objects.push_back(object); return true; } } diff --git a/planning/behavior_velocity_intersection_module/src/util.hpp b/planning/behavior_velocity_intersection_module/src/util.hpp index f103191b2dc6f..e37bb3ee88cc1 100644 --- a/planning/behavior_velocity_intersection_module/src/util.hpp +++ b/planning/behavior_velocity_intersection_module/src/util.hpp @@ -34,7 +34,6 @@ namespace behavior_velocity_planner::util { /** - * @fn * @brief insert a new pose to the path and return its index * @return if insertion was successful return the inserted point index */ @@ -44,7 +43,6 @@ std::optional insertPointIndex( const double ego_nearest_dist_threshold, const double ego_nearest_yaw_threshold); /** - * @fn * @brief check if a PathPointWithLaneId contains any of the given lane ids */ bool hasLaneIds( @@ -52,7 +50,6 @@ bool hasLaneIds( const std::set & ids); /** - * @fn * @brief find the first contiguous interval of the path points that contains the specified lane ids * @return if no interval is found, return null. if the interval [start, end] (inclusive range) is * found, returns the pair (start-1, end) @@ -61,7 +58,6 @@ std::optional> findLaneIdsInterval( const autoware_auto_planning_msgs::msg::PathWithLaneId & p, const std::set & ids); /** - * @fn * @brief return the index of the first point which is inside the given polygon * @param[in] lane_interval the interval of the path points on the intersection * @param[in] search_forward flag for search direction @@ -72,7 +68,6 @@ std::optional getFirstPointInsidePolygon( const bool search_forward = true); /** - * @fn * @brief check if ego is over the target_idx. If the index is same, compare the exact pose * @param[in] path path * @param[in] closest_idx ego's closest index on the path @@ -84,7 +79,6 @@ bool isOverTargetIndex( const geometry_msgs::msg::Pose & current_pose, const size_t target_idx); /** - * @fn * @brief check if ego is before the target_idx. If the index is same, compare the exact pose * @param[in] path path * @param[in] closest_idx ego's closest index on the path @@ -99,13 +93,11 @@ std::optional getIntersectionArea( lanelet::ConstLanelet assigned_lane, lanelet::LaneletMapConstPtr lanelet_map_ptr); /** - * @fn * @brief check if the given lane has related traffic light */ bool hasAssociatedTrafficLight(lanelet::ConstLanelet lane); /** - * @fn * @brief interpolate PathWithLaneId */ std::optional generateInterpolatedPath( @@ -117,7 +109,6 @@ geometry_msgs::msg::Pose getObjectPoseWithVelocityDirection( const autoware_auto_perception_msgs::msg::PredictedObjectKinematics & obj_state); /** - * @fn * @brief this function sorts the set of lanelets topologically using topological sort and merges * the lanelets from each root to each end. each branch is merged and returned with the original * lanelets @@ -131,7 +122,6 @@ mergeLaneletsByTopologicalSort( const lanelet::routing::RoutingGraphPtr routing_graph_ptr); /** - * @fn * @brief find the index of the first point where vehicle footprint intersects with the given * polygon */ @@ -140,6 +130,10 @@ std::optional getFirstPointInsidePolygonByFootprint( const intersection::InterpolatedPathInfo & interpolated_path_info, const tier4_autoware_utils::LinearRing2d & footprint, const double vehicle_length); +/** + * @brief find the index of the first point where vehicle footprint intersects with the given + * polygons + */ std::optional> getFirstPointInsidePolygonsByFootprint( From 6d8f026dcfa3e811ebeecd8fa72de9512ac47762 Mon Sep 17 00:00:00 2001 From: Zulfaqar Azmi <93502286+zulfaqar-azmi-t4@users.noreply.github.com> Date: Mon, 29 Jan 2024 12:52:17 +0900 Subject: [PATCH 033/132] refactor(lane_change): combine all debug data into single struct (#6173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(lane_change): combine all debug data into single struct Signed-off-by: Zulfaqar Azmi * Rename valid path → valid paths Signed-off-by: Zulfaqar Azmi * move the marker creation to marker_utils Signed-off-by: Zulfaqar Azmi * Remove alias Signed-off-by: Zulfaqar Azmi --------- Signed-off-by: Zulfaqar Azmi --- .../interface.hpp | 2 +- .../utils/base_class.hpp | 22 ++------- .../utils/debug_structs.hpp | 49 +++++++++++++++++++ .../utils/markers.hpp | 4 ++ .../src/interface.cpp | 44 ++++------------- .../src/scene.cpp | 40 +++++++-------- .../src/utils/markers.cpp | 44 +++++++++++++++++ 7 files changed, 129 insertions(+), 76 deletions(-) create mode 100644 planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/debug_structs.hpp diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/interface.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/interface.hpp index 4e741a2b3db2c..6a9a8c40c01d1 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/interface.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/interface.hpp @@ -128,7 +128,7 @@ class LaneChangeInterface : public SceneModuleInterface bool canTransitIdleToRunningState() override; - void setObjectDebugVisualization() const; + void updateDebugMarker() const; void updateSteeringFactorPtr(const BehaviorModuleOutput & output); diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp index e78d706334bae..15fe2f8d2b8d9 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/base_class.hpp @@ -15,6 +15,7 @@ #define BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__BASE_CLASS_HPP_ #include "behavior_path_lane_change_module/utils/data_structs.hpp" +#include "behavior_path_lane_change_module/utils/debug_structs.hpp" #include "behavior_path_lane_change_module/utils/path.hpp" #include "behavior_path_lane_change_module/utils/utils.hpp" #include "behavior_path_planner_common/interface/scene_module_interface.hpp" @@ -36,7 +37,6 @@ namespace behavior_path_planner { using autoware_auto_planning_msgs::msg::PathWithLaneId; -using behavior_path_planner::utils::path_safety_checker::CollisionCheckDebugMap; using data::lane_change::PathSafetyStatus; using geometry_msgs::msg::Point; using geometry_msgs::msg::Pose; @@ -137,19 +137,7 @@ class LaneChangeBase const LaneChangeStatus & getLaneChangeStatus() const { return status_; } - const LaneChangePaths & getDebugValidPath() const { return debug_valid_path_; } - - const CollisionCheckDebugMap & getDebugData() const { return object_debug_; } - - const CollisionCheckDebugMap & getAfterApprovalDebugData() const - { - return object_debug_after_approval_; - } - - const LaneChangeTargetObjects & getDebugFilteredObjects() const - { - return debug_filtered_objects_; - } + const data::lane_change::Debug & getDebugData() const { return lane_change_debug_; } const Pose & getEgoPose() const { return planner_data_->self_odometry->pose.pose; } @@ -257,12 +245,8 @@ class LaneChangeBase Direction direction_{Direction::NONE}; LaneChangeModuleType type_{LaneChangeModuleType::NORMAL}; - mutable LaneChangePaths debug_valid_path_{}; - mutable CollisionCheckDebugMap object_debug_{}; - mutable CollisionCheckDebugMap object_debug_after_approval_{}; - mutable LaneChangeTargetObjects debug_filtered_objects_{}; - mutable double object_debug_lifetime_{0.0}; mutable StopWatch stop_watch_; + mutable data::lane_change::Debug lane_change_debug_; rclcpp::Logger logger_ = utils::lane_change::getLogger(getModuleTypeStr()); mutable rclcpp::Clock clock_{RCL_ROS_TIME}; diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/debug_structs.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/debug_structs.hpp new file mode 100644 index 0000000000000..8ac1ba3909a50 --- /dev/null +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/debug_structs.hpp @@ -0,0 +1,49 @@ +// 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. +#ifndef BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__DEBUG_STRUCTS_HPP_ +#define BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__DEBUG_STRUCTS_HPP_ + +#include "behavior_path_lane_change_module/utils/data_structs.hpp" +#include "behavior_path_lane_change_module/utils/path.hpp" + +#include + +#include + +namespace behavior_path_planner::data::lane_change +{ +using utils::path_safety_checker::CollisionCheckDebugMap; +struct Debug +{ + std::string module_type; + LaneChangePaths valid_paths; + CollisionCheckDebugMap collision_check_objects; + CollisionCheckDebugMap collision_check_objects_after_approval; + LaneChangeTargetObjects filtered_objects; + double collision_check_object_debug_lifetime{0.0}; + + void reset() + { + valid_paths.clear(); + collision_check_objects.clear(); + collision_check_objects_after_approval.clear(); + filtered_objects.current_lane.clear(); + filtered_objects.target_lane.clear(); + filtered_objects.other_lane.clear(); + collision_check_object_debug_lifetime = 0.0; + } +}; +} // namespace behavior_path_planner::data::lane_change + +#endif // BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__DEBUG_STRUCTS_HPP_ diff --git a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/markers.hpp b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/markers.hpp index d6deecd4f46fa..427a26e9b4295 100644 --- a/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/markers.hpp +++ b/planning/behavior_path_lane_change_module/include/behavior_path_lane_change_module/utils/markers.hpp @@ -15,9 +15,11 @@ #ifndef BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__MARKERS_HPP_ #define BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__MARKERS_HPP_ +#include "behavior_path_lane_change_module/utils/debug_structs.hpp" #include "behavior_path_lane_change_module/utils/path.hpp" #include "behavior_path_planner_common/utils/path_safety_checker/path_safety_checker_parameters.hpp" +#include #include #include @@ -26,6 +28,7 @@ namespace marker_utils::lane_change_markers { using behavior_path_planner::LaneChangePath; +using behavior_path_planner::data::lane_change::Debug; using behavior_path_planner::utils::path_safety_checker::ExtendedPredictedObjects; using visualization_msgs::msg::MarkerArray; MarkerArray showAllValidLaneChangePath( @@ -37,5 +40,6 @@ MarkerArray showFilteredObjects( const ExtendedPredictedObjects & current_lane_objects, const ExtendedPredictedObjects & target_lane_objects, const ExtendedPredictedObjects & other_lane_objects, const std::string & ns); +MarkerArray createDebugMarkerArray(const Debug & debug_data); } // namespace marker_utils::lane_change_markers #endif // BEHAVIOR_PATH_LANE_CHANGE_MODULE__UTILS__MARKERS_HPP_ diff --git a/planning/behavior_path_lane_change_module/src/interface.cpp b/planning/behavior_path_lane_change_module/src/interface.cpp index c8e1229fe5af5..41d6b7aa6fc19 100644 --- a/planning/behavior_path_lane_change_module/src/interface.cpp +++ b/planning/behavior_path_lane_change_module/src/interface.cpp @@ -83,7 +83,7 @@ void LaneChangeInterface::updateData() if (isWaitingApproval()) { module_type_->updateLaneChangeStatus(); } - setObjectDebugVisualization(); + updateDebugMarker(); module_type_->updateSpecialData(); module_type_->resetStopPose(); @@ -109,7 +109,8 @@ BehaviorModuleOutput LaneChangeInterface::plan() stop_pose_ = module_type_->getStopPose(); - for (const auto & [uuid, data] : module_type_->getAfterApprovalDebugData()) { + const auto & lane_change_debug = module_type_->getDebugData(); + for (const auto & [uuid, data] : lane_change_debug.collision_check_objects_after_approval) { const auto color = data.is_safe ? ColorName::GREEN : ColorName::RED; setObjectsOfInterestData(data.current_obj_pose, data.obj_shape, color); } @@ -133,7 +134,8 @@ BehaviorModuleOutput LaneChangeInterface::planWaitingApproval() out.drivable_area_info = getPreviousModuleOutput().drivable_area_info; out.turn_signal_info = getCurrentTurnSignalInfo(out.path, out.turn_signal_info); - for (const auto & [uuid, data] : module_type_->getDebugData()) { + const auto & lane_change_debug = module_type_->getDebugData(); + for (const auto & [uuid, data] : lane_change_debug.collision_check_objects) { const auto color = data.is_safe ? ColorName::GREEN : ColorName::RED; setObjectsOfInterestData(data.current_obj_pose, data.obj_shape, color); } @@ -291,7 +293,7 @@ bool LaneChangeInterface::canTransitFailureState() bool LaneChangeInterface::canTransitIdleToRunningState() { - setObjectDebugVisualization(); + updateDebugMarker(); auto log_debug_throttled = [&](std::string_view message) -> void { RCLCPP_DEBUG(getLogger(), "%s", message.data()); @@ -312,43 +314,15 @@ bool LaneChangeInterface::canTransitIdleToRunningState() return true; } -void LaneChangeInterface::setObjectDebugVisualization() const +void LaneChangeInterface::updateDebugMarker() const { - debug_marker_.markers.clear(); if (!parameters_->publish_debug_marker) { return; } - using marker_utils::showPolygon; - using marker_utils::showPredictedPath; - using marker_utils::showSafetyCheckInfo; - using marker_utils::lane_change_markers::showAllValidLaneChangePath; - using marker_utils::lane_change_markers::showFilteredObjects; - - const auto debug_data = module_type_->getDebugData(); - const auto debug_after_approval = module_type_->getAfterApprovalDebugData(); - const auto debug_valid_path = module_type_->getDebugValidPath(); - const auto debug_filtered_objects = module_type_->getDebugFilteredObjects(); debug_marker_.markers.clear(); - const auto add = [this](const MarkerArray & added) { - tier4_autoware_utils::appendMarkerArray(added, &debug_marker_); - }; - - add(showAllValidLaneChangePath(debug_valid_path, "lane_change_valid_paths")); - add(showFilteredObjects( - debug_filtered_objects.current_lane, debug_filtered_objects.target_lane, - debug_filtered_objects.other_lane, "object_filtered")); - if (!debug_data.empty()) { - add(showSafetyCheckInfo(debug_data, "object_debug_info")); - add(showPredictedPath(debug_data, "ego_predicted_path")); - add(showPolygon(debug_data, "ego_and_target_polygon_relation")); - } - - if (!debug_after_approval.empty()) { - add(showSafetyCheckInfo(debug_after_approval, "object_debug_info_after_approval")); - add(showPredictedPath(debug_after_approval, "ego_predicted_path_after_approval")); - add(showPolygon(debug_after_approval, "ego_and_target_polygon_relation_after_approval")); - } + using marker_utils::lane_change_markers::createDebugMarkerArray; + debug_marker_ = createDebugMarkerArray(module_type_->getDebugData()); } MarkerArray LaneChangeInterface::getModuleVirtualWall() diff --git a/planning/behavior_path_lane_change_module/src/scene.cpp b/planning/behavior_path_lane_change_module/src/scene.cpp index b115ab7c163c0..b56e9e544ea8d 100644 --- a/planning/behavior_path_lane_change_module/src/scene.cpp +++ b/planning/behavior_path_lane_change_module/src/scene.cpp @@ -97,7 +97,7 @@ std::pair NormalLaneChange::getSafePath(LaneChangePath & safe_path) lane_change_parameters_->rss_params_for_stuck, is_stuck); } - debug_valid_path_ = valid_paths; + lane_change_debug_.valid_paths = valid_paths; if (valid_paths.empty()) { safe_path.info.current_lanes = current_lanes; @@ -421,13 +421,8 @@ void NormalLaneChange::resetParameters() current_lane_change_state_ = LaneChangeStates::Normal; abort_path_ = nullptr; status_ = {}; + lane_change_debug_.reset(); - object_debug_.clear(); - object_debug_after_approval_.clear(); - debug_filtered_objects_.current_lane.clear(); - debug_filtered_objects_.target_lane.clear(); - debug_filtered_objects_.other_lane.clear(); - debug_valid_path_.clear(); RCLCPP_DEBUG(logger_, "reset all flags and debug information."); } @@ -1112,7 +1107,7 @@ bool NormalLaneChange::getLaneChangePaths( const utils::path_safety_checker::RSSparams rss_params, const bool is_stuck, const bool check_safety) const { - object_debug_.clear(); + lane_change_debug_.collision_check_objects.clear(); if (current_lanes.empty() || target_lanes.empty()) { RCLCPP_WARN(logger_, "target_neighbor_preferred_lane_poly_2d is empty. Not expected."); return false; @@ -1158,7 +1153,7 @@ bool NormalLaneChange::getLaneChangePaths( } const auto target_objects = getTargetObjects(current_lanes, target_lanes); - debug_filtered_objects_ = target_objects; + lane_change_debug_.filtered_objects = target_objects; const auto prepare_durations = calcPrepareDuration(current_lanes, target_lanes); @@ -1385,9 +1380,10 @@ bool NormalLaneChange::getLaneChangePaths( std::vector filtered_objects = filterObjectsInTargetLane(target_objects, target_lanes); if ( - !is_stuck && utils::lane_change::passParkedObject( - route_handler, *candidate_path, filtered_objects, lane_change_buffer, - is_goal_in_route, *lane_change_parameters_, object_debug_)) { + !is_stuck && + utils::lane_change::passParkedObject( + route_handler, *candidate_path, filtered_objects, lane_change_buffer, is_goal_in_route, + *lane_change_parameters_, lane_change_debug_.collision_check_objects)) { debug_print( "Reject: parking vehicle exists in the target lane, and the ego is not in stuck. Skip " "lane change."); @@ -1400,7 +1396,8 @@ bool NormalLaneChange::getLaneChangePaths( } const auto [is_safe, is_object_coming_from_rear] = isLaneChangePathSafe( - *candidate_path, target_objects, rss_params, is_stuck, object_debug_); + *candidate_path, target_objects, rss_params, is_stuck, + lane_change_debug_.collision_check_objects); if (is_safe) { debug_print("ACCEPT!!!: it is valid and safe!"); @@ -1423,7 +1420,7 @@ PathSafetyStatus NormalLaneChange::isApprovedPathSafe() const const auto & target_lanes = status_.target_lanes; const auto target_objects = getTargetObjects(current_lanes, target_lanes); - debug_filtered_objects_ = target_objects; + lane_change_debug_.filtered_objects = target_objects; CollisionCheckDebugMap debug_data; const bool is_stuck = isVehicleStuck(current_lanes); @@ -1431,16 +1428,17 @@ PathSafetyStatus NormalLaneChange::isApprovedPathSafe() const path, target_objects, lane_change_parameters_->rss_params_for_abort, is_stuck, debug_data); { // only for debug purpose - object_debug_.clear(); - object_debug_lifetime_ += (stop_watch_.toc(getModuleTypeStr()) / 1000); - if (object_debug_lifetime_ > 2.0) { + lane_change_debug_.collision_check_objects.clear(); + lane_change_debug_.collision_check_object_debug_lifetime += + (stop_watch_.toc(getModuleTypeStr()) / 1000); + if (lane_change_debug_.collision_check_object_debug_lifetime > 2.0) { stop_watch_.toc(getModuleTypeStr(), true); - object_debug_lifetime_ = 0.0; - object_debug_after_approval_.clear(); + lane_change_debug_.collision_check_object_debug_lifetime = 0.0; + lane_change_debug_.collision_check_objects_after_approval.clear(); } if (!safety_status.is_safe) { - object_debug_after_approval_ = debug_data; + lane_change_debug_.collision_check_objects_after_approval = debug_data; } } @@ -1802,7 +1800,7 @@ bool NormalLaneChange::isVehicleStuck( using lanelet::utils::getArcCoordinates; const auto base_distance = getArcCoordinates(current_lanes, getEgoPose()).length; - for (const auto & object : debug_filtered_objects_.current_lane) { + for (const auto & object : lane_change_debug_.filtered_objects.current_lane) { const auto & p = object.initial_pose.pose; // TODO(Horibe): consider footprint point // Note: it needs chattering prevention. diff --git a/planning/behavior_path_lane_change_module/src/utils/markers.cpp b/planning/behavior_path_lane_change_module/src/utils/markers.cpp index 719acba405a68..523b770734bc5 100644 --- a/planning/behavior_path_lane_change_module/src/utils/markers.cpp +++ b/planning/behavior_path_lane_change_module/src/utils/markers.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -120,4 +121,47 @@ MarkerArray showFilteredObjects( marker_array.markers.end(), other_marker.markers.begin(), other_marker.markers.end()); return marker_array; } + +MarkerArray createDebugMarkerArray(const Debug & debug_data) +{ + using marker_utils::showPolygon; + using marker_utils::showPredictedPath; + using marker_utils::showSafetyCheckInfo; + using marker_utils::lane_change_markers::showAllValidLaneChangePath; + using marker_utils::lane_change_markers::showFilteredObjects; + + const auto & debug_collision_check_object = debug_data.collision_check_objects; + const auto & debug_collision_check_object_after_approval = + debug_data.collision_check_objects_after_approval; + const auto & debug_valid_paths = debug_data.valid_paths; + const auto & debug_filtered_objects = debug_data.filtered_objects; + + MarkerArray debug_marker; + const auto add = [&debug_marker](const MarkerArray & added) { + tier4_autoware_utils::appendMarkerArray(added, &debug_marker); + }; + + add(showAllValidLaneChangePath(debug_valid_paths, "lane_change_valid_paths")); + add(showFilteredObjects( + debug_filtered_objects.current_lane, debug_filtered_objects.target_lane, + debug_filtered_objects.other_lane, "object_filtered")); + + if (!debug_collision_check_object.empty()) { + add(showSafetyCheckInfo(debug_collision_check_object, "collision_check_object_info")); + add(showPredictedPath(debug_collision_check_object, "ego_predicted_path")); + add(showPolygon(debug_collision_check_object, "ego_and_target_polygon_relation")); + } + + if (!debug_collision_check_object_after_approval.empty()) { + add(showSafetyCheckInfo( + debug_collision_check_object_after_approval, "object_debug_info_after_approval")); + add(showPredictedPath( + debug_collision_check_object_after_approval, "ego_predicted_path_after_approval")); + add(showPolygon( + debug_collision_check_object_after_approval, + "ego_and_target_polygon_relation_after_approval")); + } + + return debug_marker; +} } // namespace marker_utils::lane_change_markers From daf082474c3e286949f132ed7b0b5ad02b65d224 Mon Sep 17 00:00:00 2001 From: kminoda <44218668+kminoda@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:01:37 +0900 Subject: [PATCH 034/132] fix(tier4_perception_launch): fix a bug in #6159 (#6203) Signed-off-by: kminoda --- launch/tier4_perception_launch/launch/perception.launch.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launch/tier4_perception_launch/launch/perception.launch.xml b/launch/tier4_perception_launch/launch/perception.launch.xml index 3bd3aff10a4e4..e8c19382864ba 100644 --- a/launch/tier4_perception_launch/launch/perception.launch.xml +++ b/launch/tier4_perception_launch/launch/perception.launch.xml @@ -16,8 +16,8 @@ - - + + From f9ed5b0ff141c0aaac62b523129282a925437430 Mon Sep 17 00:00:00 2001 From: Yoshi Ri Date: Mon, 29 Jan 2024 15:06:46 +0900 Subject: [PATCH 035/132] fix(tracking_object_merger): enable to association unknown class in tracker merger (#6182) * fix: enable to association unknown class in tracker merger Signed-off-by: yoshiri * chore: disable warning messages caused by unknown association Signed-off-by: yoshiri --------- Signed-off-by: yoshiri --- .../config/data_association_matrix.param.yaml | 6 +++--- perception/tracking_object_merger/src/utils/utils.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/perception/tracking_object_merger/config/data_association_matrix.param.yaml b/perception/tracking_object_merger/config/data_association_matrix.param.yaml index 702809b3cede1..c232dbde40b51 100644 --- a/perception/tracking_object_merger/config/data_association_matrix.param.yaml +++ b/perception/tracking_object_merger/config/data_association_matrix.param.yaml @@ -3,7 +3,7 @@ lidar-lidar: can_assign_matrix: #UNKNOWN, CAR, TRUCK, BUS, TRAILER, MOTORBIKE, BICYCLE,PEDESTRIAN - [0, 0, 0, 0, 0, 0, 0, 0, #UNKNOWN + [1, 0, 0, 0, 0, 0, 0, 0, #UNKNOWN 0, 1, 1, 1, 1, 0, 0, 0, #CAR 0, 1, 1, 1, 1, 0, 0, 0, #TRUCK 0, 1, 1, 1, 1, 0, 0, 0, #BUS @@ -59,7 +59,7 @@ lidar-radar: can_assign_matrix: #UNKNOWN, CAR, TRUCK, BUS, TRAILER, MOTORBIKE, BICYCLE,PEDESTRIAN - [0, 0, 0, 0, 0, 0, 0, 0, #UNKNOWN + [1, 0, 0, 0, 0, 0, 0, 0, #UNKNOWN 0, 1, 1, 1, 1, 0, 0, 0, #CAR 0, 1, 1, 1, 1, 0, 0, 0, #TRUCK 0, 1, 1, 1, 1, 0, 0, 0, #BUS @@ -115,7 +115,7 @@ radar-radar: can_assign_matrix: #UNKNOWN, CAR, TRUCK, BUS, TRAILER, MOTORBIKE, BICYCLE,PEDESTRIAN - [0, 0, 0, 0, 0, 0, 0, 0, #UNKNOWN + [1, 0, 0, 0, 0, 0, 0, 0, #UNKNOWN 0, 1, 1, 1, 1, 0, 0, 0, #CAR 0, 1, 1, 1, 1, 0, 0, 0, #TRUCK 0, 1, 1, 1, 1, 0, 0, 0, #BUS diff --git a/perception/tracking_object_merger/src/utils/utils.cpp b/perception/tracking_object_merger/src/utils/utils.cpp index 81f63538f9e22..85ab105e61038 100644 --- a/perception/tracking_object_merger/src/utils/utils.cpp +++ b/perception/tracking_object_merger/src/utils/utils.cpp @@ -484,9 +484,9 @@ void updateWholeTrackedObject(TrackedObject & main_obj, const TrackedObject & su { if (!objectsHaveSameMotionDirections(main_obj, sub_obj)) { // warning - std::cerr << "[object_tracking_merger]: motion direction is different in " - "updateWholeTrackedObject function." - << std::endl; + // std::cerr << "[object_tracking_merger]: motion direction is different in " + // "updateWholeTrackedObject function." + // << std::endl; } main_obj = sub_obj; } From f6e4550c9de48136ba809d5de5e96d0473a11a4b Mon Sep 17 00:00:00 2001 From: Yamato Ando Date: Mon, 29 Jan 2024 16:25:09 +0900 Subject: [PATCH 036/132] refactor(ndt_scan_matcher): rename de-grounded (#6186) * refactor(ndt_scan_matcher): rename de-grounded Signed-off-by: Yamato Ando * style(pre-commit): autofix --------- Signed-off-by: Yamato Ando Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- localization/ndt_scan_matcher/README.md | 18 ++++++++---------- .../config/ndt_scan_matcher.param.yaml | 5 ++--- .../ndt_scan_matcher/ndt_scan_matcher_core.hpp | 3 +-- .../src/ndt_scan_matcher_core.cpp | 9 ++++----- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/localization/ndt_scan_matcher/README.md b/localization/ndt_scan_matcher/README.md index 95a7cebdc01c8..7956a663f92d5 100644 --- a/localization/ndt_scan_matcher/README.md +++ b/localization/ndt_scan_matcher/README.md @@ -31,13 +31,13 @@ One optional function is regularization. Please see the regularization chapter i | `ndt_pose_with_covariance` | `geometry_msgs::msg::PoseWithCovarianceStamped` | estimated pose with covariance | | `/diagnostics` | `diagnostic_msgs::msg::DiagnosticArray` | diagnostics | | `points_aligned` | `sensor_msgs::msg::PointCloud2` | [debug topic] pointcloud aligned by scan matching | -| `points_aligned_no_ground` | `sensor_msgs::msg::PointCloud2` | [debug topic] de-grounded pointcloud aligned by scan matching | +| `points_aligned_no_ground` | `sensor_msgs::msg::PointCloud2` | [debug topic] no ground pointcloud aligned by scan matching | | `initial_pose_with_covariance` | `geometry_msgs::msg::PoseWithCovarianceStamped` | [debug topic] initial pose used in scan matching | | `multi_ndt_pose` | `geometry_msgs::msg::PoseArray` | [debug topic] estimated poses from multiple initial poses in real-time covariance estimation | | `multi_initial_pose` | `geometry_msgs::msg::PoseArray` | [debug topic] initial poses for real-time covariance estimation | | `exe_time_ms` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] execution time for scan matching [ms] | | `transform_probability` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] score of scan matching | -| `no_ground_transform_probability` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] score of scan matching based on de-grounded LiDAR scan | +| `no_ground_transform_probability` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] score of scan matching based on no ground LiDAR scan | | `iteration_num` | `tier4_debug_msgs::msg::Int32Stamped` | [debug topic] number of scan matching iterations | | `initial_to_result_relative_pose` | `geometry_msgs::msg::PoseStamped` | [debug topic] relative pose between the initial point and the convergence point | | `initial_to_result_distance` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] distance difference between the initial point and the convergence point [m] | @@ -228,21 +228,19 @@ Here is a split PCD map for `sample-map-rosbag` from Autoware tutorial: [`sample | single file | at once (standard) | | multiple files | dynamically | -## Scan matching score based on de-grounded LiDAR scan +## Scan matching score based on no ground LiDAR scan ### Abstract -This is a function that uses de-grounded LiDAR scan to estimate the scan matching score. This score can reflect the current localization performance more accurately. +This is a function that uses no ground LiDAR scan to estimate the scan matching score. This score can reflect the current localization performance more accurately. [related issue](https://github.com/autowarefoundation/autoware.universe/issues/2044). ### Parameters - - -| Name | Type | Description | -| ------------------------------------- | ------ | ------------------------------------------------------------------------------------- | -| `estimate_scores_for_degrounded_scan` | bool | Flag for using scan matching score based on de-grounded LiDAR scan (FALSE by default) | -| `z_margin_for_ground_removal` | double | Z-value margin for removal ground points | +| Name | Type | Description | +| ------------------------------------- | ------ | ----------------------------------------------------------------------------------- | +| `estimate_scores_by_no_ground_points` | bool | Flag for using scan matching score based on no ground LiDAR scan (FALSE by default) | +| `z_margin_for_ground_removal` | double | Z-value margin for removal ground points | ## 2D real-time covariance estimation diff --git a/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml b/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml index a5a4941bfec62..d4c49b7e8eec5 100644 --- a/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml +++ b/localization/ndt_scan_matcher/config/ndt_scan_matcher.param.yaml @@ -95,9 +95,8 @@ # Radius of input LiDAR range (used for diagnostics of dynamic map loading) lidar_radius: 100.0 - # cspell: ignore degrounded - # A flag for using scan matching score based on de-grounded LiDAR scan - estimate_scores_for_degrounded_scan: false + # A flag for using scan matching score based on no ground LiDAR scan + estimate_scores_by_no_ground_points: false # If lidar_point.z - base_link.z <= this threshold , the point will be removed z_margin_for_ground_removal: 0.8 diff --git a/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp b/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp index e2503c20aef6e..2883aa761444d 100644 --- a/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp +++ b/localization/ndt_scan_matcher/include/ndt_scan_matcher/ndt_scan_matcher_core.hpp @@ -220,8 +220,7 @@ class NDTScanMatcher : public rclcpp::Node std::unique_ptr map_update_module_; std::unique_ptr logger_configure_; - // cspell: ignore degrounded - bool estimate_scores_for_degrounded_scan_; + bool estimate_scores_by_no_ground_points_; double z_margin_for_ground_removal_; // The execution time which means probably NDT cannot matches scans properly diff --git a/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp b/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp index 0382d805b7276..0278a62341981 100644 --- a/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp +++ b/localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp @@ -64,7 +64,6 @@ Eigen::Matrix2d find_rotation_matrix_aligning_covariance_to_principal_axes( throw std::runtime_error("Eigen solver failed. Return output_pose_covariance value."); } -// cspell: ignore degrounded NDTScanMatcher::NDTScanMatcher() : Node("ndt_scan_matcher"), tf2_broadcaster_(*this), @@ -160,8 +159,8 @@ NDTScanMatcher::NDTScanMatcher() this->declare_parameter("initial_estimate_particles_num"); n_startup_trials_ = this->declare_parameter("n_startup_trials"); - estimate_scores_for_degrounded_scan_ = - this->declare_parameter("estimate_scores_for_degrounded_scan"); + estimate_scores_by_no_ground_points_ = + this->declare_parameter("estimate_scores_by_no_ground_points"); z_margin_for_ground_removal_ = this->declare_parameter("z_margin_for_ground_removal"); @@ -526,8 +525,8 @@ void NDTScanMatcher::callback_sensor_points( *sensor_points_in_baselink_frame, *sensor_points_in_map_ptr, ndt_result.pose); publish_point_cloud(sensor_ros_time, map_frame_, sensor_points_in_map_ptr); - // whether use de-grounded points calculate score - if (estimate_scores_for_degrounded_scan_) { + // whether use no ground points to calculate score + if (estimate_scores_by_no_ground_points_) { // remove ground pcl::shared_ptr> no_ground_points_in_map_ptr( new pcl::PointCloud); From d57381b6da871c435f41c00c247aa6e226c37bca Mon Sep 17 00:00:00 2001 From: Satoshi Tanaka <16330533+scepter914@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:40:29 +0900 Subject: [PATCH 037/132] fix(simple_object_merger): change the default param of timeout_threshold (#6133) * fix(simple_object_merger): change the default param of timeout_threshold Signed-off-by: scepter914 * fix conflict Signed-off-by: scepter914 --------- Signed-off-by: scepter914 --- .../simple_object_merger/launch/simple_object_merger.launch.xml | 2 +- .../src/simple_object_merger_node/simple_object_merger_node.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/perception/simple_object_merger/launch/simple_object_merger.launch.xml b/perception/simple_object_merger/launch/simple_object_merger.launch.xml index 14fca01fa6438..ccd038c23b257 100644 --- a/perception/simple_object_merger/launch/simple_object_merger.launch.xml +++ b/perception/simple_object_merger/launch/simple_object_merger.launch.xml @@ -4,7 +4,7 @@ - + diff --git a/perception/simple_object_merger/src/simple_object_merger_node/simple_object_merger_node.cpp b/perception/simple_object_merger/src/simple_object_merger_node/simple_object_merger_node.cpp index 693fccb7e937c..683c6921eef5b 100644 --- a/perception/simple_object_merger/src/simple_object_merger_node/simple_object_merger_node.cpp +++ b/perception/simple_object_merger/src/simple_object_merger_node/simple_object_merger_node.cpp @@ -82,7 +82,7 @@ SimpleObjectMergerNode::SimpleObjectMergerNode(const rclcpp::NodeOptions & node_ // Node Parameter node_param_.update_rate_hz = declare_parameter("update_rate_hz", 20.0); node_param_.new_frame_id = declare_parameter("new_frame_id", "base_link"); - node_param_.timeout_threshold = declare_parameter("timeout_threshold", 1.0); + node_param_.timeout_threshold = declare_parameter("timeout_threshold", 0.1); declare_parameter("input_topics", std::vector()); node_param_.topic_names = get_parameter("input_topics").as_string_array(); From 43100454f9b49c24773f26d8870038f7fdd73129 Mon Sep 17 00:00:00 2001 From: Mamoru Sobue Date: Mon, 29 Jan 2024 16:44:55 +0900 Subject: [PATCH 038/132] feat(intersection, blind_spot): add objects of interest marker (#6201) Signed-off-by: Mamoru Sobue --- planning/behavior_velocity_blind_spot_module/src/scene.cpp | 4 +++- planning/behavior_velocity_blind_spot_module/src/scene.hpp | 2 +- .../src/scene_intersection_collision.cpp | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/planning/behavior_velocity_blind_spot_module/src/scene.cpp b/planning/behavior_velocity_blind_spot_module/src/scene.cpp index efbff7e2af51d..54314e50308ff 100644 --- a/planning/behavior_velocity_blind_spot_module/src/scene.cpp +++ b/planning/behavior_velocity_blind_spot_module/src/scene.cpp @@ -348,7 +348,7 @@ bool BlindSpotModule::checkObstacleInBlindSpot( lanelet::LaneletMapConstPtr lanelet_map_ptr, lanelet::routing::RoutingGraphPtr routing_graph_ptr, const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const autoware_auto_perception_msgs::msg::PredictedObjects::ConstSharedPtr objects_ptr, - const int closest_idx, const geometry_msgs::msg::Pose & stop_line_pose) const + const int closest_idx, const geometry_msgs::msg::Pose & stop_line_pose) { /* get detection area */ if (turn_direction_ == TurnDirection::INVALID) { @@ -409,6 +409,8 @@ bool BlindSpotModule::checkObstacleInBlindSpot( exist_in_right_conflict_area || exist_in_opposite_conflict_area; if (exist_in_detection_area && exist_in_conflict_area) { debug_data_.conflicting_targets.objects.push_back(object); + setObjectsOfInterestData( + object.kinematics.initial_pose_with_covariance.pose, object.shape, ColorName::RED); return true; } } diff --git a/planning/behavior_velocity_blind_spot_module/src/scene.hpp b/planning/behavior_velocity_blind_spot_module/src/scene.hpp index 6f8450568939c..2ca2fe7950989 100644 --- a/planning/behavior_velocity_blind_spot_module/src/scene.hpp +++ b/planning/behavior_velocity_blind_spot_module/src/scene.hpp @@ -113,7 +113,7 @@ class BlindSpotModule : public SceneModuleInterface lanelet::routing::RoutingGraphPtr routing_graph_ptr, const autoware_auto_planning_msgs::msg::PathWithLaneId & path, const autoware_auto_perception_msgs::msg::PredictedObjects::ConstSharedPtr objects_ptr, - const int closest_idx, const geometry_msgs::msg::Pose & stop_line_pose) const; + const int closest_idx, const geometry_msgs::msg::Pose & stop_line_pose); /** * @brief Create half lanelet diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp b/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp index 4f7e8b45d107f..4496df77134e2 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection_collision.cpp @@ -621,6 +621,9 @@ IntersectionModule::CollisionStatus IntersectionModule::detectCollision( continue; } const auto & unsafe_info = object_info->is_unsafe().value(); + setObjectsOfInterestData( + object_info->predicted_object().kinematics.initial_pose_with_covariance.pose, + object_info->predicted_object().shape, ColorName::RED); // ========================================================================================== // if ego is over the pass judge lines, then the visualization as "too_late_objects" or // "misjudge_objects" is more important than that for "unsafe" @@ -910,7 +913,7 @@ bool IntersectionModule::checkCollision( } } object_ttc_time_array.layout.dim.at(0).size++; - const auto & pos = object.kinematics.initial_pose_with_covariance.pose.position; + const auto & pos = object..position; const auto & shape = object.shape; object_ttc_time_array.data.insert( object_ttc_time_array.data.end(), From 685b5b68098cd0f19c1c9de04646949fb805b208 Mon Sep 17 00:00:00 2001 From: kminoda <44218668+kminoda@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:17:26 +0900 Subject: [PATCH 039/132] fix(tracking_object_merger): fix bug and rework parameters (#6168) * chore(tracking_object_merger): use config Signed-off-by: kminoda * fix(tracking_object_merger): fix bug and use param file Signed-off-by: kminoda * Update perception/tracking_object_merger/config/decorative_tracker_merger.param.yaml --------- Signed-off-by: kminoda Co-authored-by: Yoshi Ri --- .../config/decorative_tracker_merger.param.yaml | 2 +- .../launch/decorative_tracker_merger.launch.xml | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/perception/tracking_object_merger/config/decorative_tracker_merger.param.yaml b/perception/tracking_object_merger/config/decorative_tracker_merger.param.yaml index 4a108be657a27..92a7fca229818 100644 --- a/perception/tracking_object_merger/config/decorative_tracker_merger.param.yaml +++ b/perception/tracking_object_merger/config/decorative_tracker_merger.param.yaml @@ -23,4 +23,4 @@ # logging settings enable_logging: false - log_file_path: "/tmp/decorative_tracker_merger.log" + logging_file_path: "association_log.json" diff --git a/perception/tracking_object_merger/launch/decorative_tracker_merger.launch.xml b/perception/tracking_object_merger/launch/decorative_tracker_merger.launch.xml index 5affbe474e8ae..52b0841f97e97 100644 --- a/perception/tracking_object_merger/launch/decorative_tracker_merger.launch.xml +++ b/perception/tracking_object_merger/launch/decorative_tracker_merger.launch.xml @@ -5,8 +5,6 @@ - - @@ -15,7 +13,5 @@ - - From 2f761e1b0382036b76ba6eb584b28b1a66cf070c Mon Sep 17 00:00:00 2001 From: TaikiYamada4 <129915538+TaikiYamada4@users.noreply.github.com> Date: Mon, 29 Jan 2024 18:56:58 +0900 Subject: [PATCH 040/132] feat(imu_corrector): changed publication algorithm and content of /diagnostics in gyro_bias_estimator (#6139) * Let diagnostics be updated even if expections occur in timer_callback Signed-off-by: TaikiYamada4 * Fixed the summary message to be "Not updated" when the gyro bias is not updated. Fixed typo. Signed-off-by: TaikiYamada4 * Removed force_update() since updater_ originaly updates diagnostics automatically. Set the update peirod of diagnostics to be same to the timer_callback. Changed words of the diagnostics message a bit. Signed-off-by: TaikiYamada4 * style(pre-commit): autofix * Let the period of diagnostics publication independent to timer. Let update_diagnostics to be simple. Signed-off-by: TaikiYamada4 * style(pre-commit): autofix * Fixed typo Signed-off-by: TaikiYamada4 * style(pre-commit): autofix * Added setPeriod after force_update to reset the timer of updater_. Then, there will be no duplicates of diagnostics. Signed-off-by: TaikiYamada4 * style(pre-commit): autofix * Set diagnostics values to have the same precision Added gyro_bias_threshold_ to the diagnostics Signed-off-by: TaikiYamada4 * Updated README.md to match the paramters in gyro_bias_estimator Signed-off-by: TaikiYamada4 * style(pre-commit): autofix --------- Signed-off-by: TaikiYamada4 Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- sensing/imu_corrector/README.md | 6 +- .../config/gyro_bias_estimator.param.yaml | 1 + .../imu_corrector/src/gyro_bias_estimator.cpp | 99 +++++++++++++------ .../imu_corrector/src/gyro_bias_estimator.hpp | 16 +++ 4 files changed, 89 insertions(+), 33 deletions(-) diff --git a/sensing/imu_corrector/README.md b/sensing/imu_corrector/README.md index 7af82c1129aff..2df12c94b7d3b 100644 --- a/sensing/imu_corrector/README.md +++ b/sensing/imu_corrector/README.md @@ -70,11 +70,11 @@ In the future, with careful implementation for pose errors, the IMU bias estimat ### Parameters +Note that this node also uses `angular_velocity_offset_x`, `angular_velocity_offset_y`, `angular_velocity_offset_z` parameters from `imu_corrector.param.yaml`. + | Name | Type | Description | | ------------------------------------- | ------ | ------------------------------------------------------------------------------------------- | -| `angular_velocity_offset_x` | double | roll rate offset in imu_link [rad/s] | -| `angular_velocity_offset_y` | double | pitch rate offset imu_link [rad/s] | -| `angular_velocity_offset_z` | double | yaw rate offset imu_link [rad/s] | | `gyro_bias_threshold` | double | threshold of the bias of the gyroscope [rad/s] | | `timer_callback_interval_sec` | double | seconds about the timer callback function [sec] | +| `diagnostics_updater_interval_sec` | double | period of the diagnostics updater [sec] | | `straight_motion_ang_vel_upper_limit` | double | upper limit of yaw angular velocity, beyond which motion is not considered straight [rad/s] | diff --git a/sensing/imu_corrector/config/gyro_bias_estimator.param.yaml b/sensing/imu_corrector/config/gyro_bias_estimator.param.yaml index e10329c920137..eac423f94fa78 100644 --- a/sensing/imu_corrector/config/gyro_bias_estimator.param.yaml +++ b/sensing/imu_corrector/config/gyro_bias_estimator.param.yaml @@ -2,4 +2,5 @@ ros__parameters: gyro_bias_threshold: 0.0015 # [rad/s] timer_callback_interval_sec: 0.5 # [sec] + diagnostics_updater_interval_sec: 0.5 # [sec] straight_motion_ang_vel_upper_limit: 0.015 # [rad/s] diff --git a/sensing/imu_corrector/src/gyro_bias_estimator.cpp b/sensing/imu_corrector/src/gyro_bias_estimator.cpp index 50e4a702ec949..e99667ed1c4a6 100644 --- a/sensing/imu_corrector/src/gyro_bias_estimator.cpp +++ b/sensing/imu_corrector/src/gyro_bias_estimator.cpp @@ -30,6 +30,7 @@ GyroBiasEstimator::GyroBiasEstimator() angular_velocity_offset_y_(declare_parameter("angular_velocity_offset_y")), angular_velocity_offset_z_(declare_parameter("angular_velocity_offset_z")), timer_callback_interval_sec_(declare_parameter("timer_callback_interval_sec")), + diagnostics_updater_interval_sec_(declare_parameter("diagnostics_updater_interval_sec")), straight_motion_ang_vel_upper_limit_( declare_parameter("straight_motion_ang_vel_upper_limit")), updater_(this), @@ -37,6 +38,8 @@ GyroBiasEstimator::GyroBiasEstimator() { updater_.setHardwareID(get_name()); updater_.add("gyro_bias_validator", this, &GyroBiasEstimator::update_diagnostics); + // diagnostic_updater is designed to be updated at the same rate as the timer + updater_.setPeriod(diagnostics_updater_interval_sec_); gyro_bias_estimation_module_ = std::make_unique(); @@ -57,6 +60,18 @@ GyroBiasEstimator::GyroBiasEstimator() this->get_node_timers_interface()->add_timer(timer_, nullptr); transform_listener_ = std::make_shared(this); + + // initialize diagnostics_info_ + { + diagnostics_info_.level = diagnostic_msgs::msg::DiagnosticStatus::OK; + diagnostics_info_.summary_message = "Not initialized"; + diagnostics_info_.gyro_bias_x_for_imu_corrector = std::nan(""); + diagnostics_info_.gyro_bias_y_for_imu_corrector = std::nan(""); + diagnostics_info_.gyro_bias_z_for_imu_corrector = std::nan(""); + diagnostics_info_.estimated_gyro_bias_x = std::nan(""); + diagnostics_info_.estimated_gyro_bias_y = std::nan(""); + diagnostics_info_.estimated_gyro_bias_z = std::nan(""); + } } void GyroBiasEstimator::callback_imu(const Imu::ConstSharedPtr imu_msg_ptr) @@ -99,6 +114,7 @@ void GyroBiasEstimator::callback_odom(const Odometry::ConstSharedPtr odom_msg_pt void GyroBiasEstimator::timer_callback() { if (pose_buf_.empty()) { + diagnostics_info_.summary_message = "Skipped update (pose_buf is empty)"; return; } @@ -112,6 +128,7 @@ void GyroBiasEstimator::timer_callback() const rclcpp::Time t0_rclcpp_time = rclcpp::Time(pose_buf.front().header.stamp); const rclcpp::Time t1_rclcpp_time = rclcpp::Time(pose_buf.back().header.stamp); if (t1_rclcpp_time <= t0_rclcpp_time) { + diagnostics_info_.summary_message = "Skipped update (pose_buf is not in chronological order)"; return; } @@ -127,6 +144,7 @@ void GyroBiasEstimator::timer_callback() // Check gyro data size // Data size must be greater than or equal to 2 since the time difference will be taken later if (gyro_filtered.size() <= 1) { + diagnostics_info_.summary_message = "Skipped update (gyro_filtered size is less than 2)"; return; } @@ -140,6 +158,8 @@ void GyroBiasEstimator::timer_callback() const double yaw_vel = yaw_diff / time_diff; const bool is_straight = (yaw_vel < straight_motion_ang_vel_upper_limit_); if (!is_straight) { + diagnostics_info_.summary_message = + "Skipped update (yaw angular velocity is greater than straight_motion_ang_vel_upper_limit)"; return; } @@ -151,12 +171,45 @@ void GyroBiasEstimator::timer_callback() if (!tf_base2imu_ptr) { RCLCPP_ERROR( this->get_logger(), "Please publish TF %s to %s", imu_frame_.c_str(), output_frame_.c_str()); + + diagnostics_info_.summary_message = "Skipped update (tf between base and imu is not available)"; return; } + gyro_bias_ = transform_vector3(gyro_bias_estimation_module_->get_bias_base_link(), *tf_base2imu_ptr); + validate_gyro_bias(); updater_.force_update(); + updater_.setPeriod(diagnostics_updater_interval_sec_); // to reset timer inside the updater +} + +void GyroBiasEstimator::validate_gyro_bias() +{ + // Calculate diagnostics key-values + diagnostics_info_.gyro_bias_x_for_imu_corrector = gyro_bias_.value().x; + diagnostics_info_.gyro_bias_y_for_imu_corrector = gyro_bias_.value().y; + diagnostics_info_.gyro_bias_z_for_imu_corrector = gyro_bias_.value().z; + diagnostics_info_.estimated_gyro_bias_x = gyro_bias_.value().x - angular_velocity_offset_x_; + diagnostics_info_.estimated_gyro_bias_y = gyro_bias_.value().y - angular_velocity_offset_y_; + diagnostics_info_.estimated_gyro_bias_z = gyro_bias_.value().z - angular_velocity_offset_z_; + + // Validation + const bool is_bias_small_enough = + std::abs(diagnostics_info_.estimated_gyro_bias_x) < gyro_bias_threshold_ && + std::abs(diagnostics_info_.estimated_gyro_bias_y) < gyro_bias_threshold_ && + std::abs(diagnostics_info_.estimated_gyro_bias_z) < gyro_bias_threshold_; + + // Update diagnostics + if (is_bias_small_enough) { + diagnostics_info_.level = diagnostic_msgs::msg::DiagnosticStatus::OK; + diagnostics_info_.summary_message = "Successfully updated"; + } else { + diagnostics_info_.level = diagnostic_msgs::msg::DiagnosticStatus::WARN; + diagnostics_info_.summary_message = + "Gyro bias may be incorrect. Please calibrate IMU and reflect the result in imu_corrector. " + "You may also use the output of gyro_bias_estimator."; + } } geometry_msgs::msg::Vector3 GyroBiasEstimator::transform_vector3( @@ -172,36 +225,22 @@ geometry_msgs::msg::Vector3 GyroBiasEstimator::transform_vector3( void GyroBiasEstimator::update_diagnostics(diagnostic_updater::DiagnosticStatusWrapper & stat) { - if (gyro_bias_ == std::nullopt) { - stat.add("gyro_bias", "Bias estimation is not yet ready because of insufficient data."); - stat.summary(diagnostic_msgs::msg::DiagnosticStatus::OK, "Not initialized"); - } else { - stat.add("gyro_bias_x_for_imu_corrector", gyro_bias_.value().x); - stat.add("gyro_bias_y_for_imu_corrector", gyro_bias_.value().y); - stat.add("gyro_bias_z_for_imu_corrector", gyro_bias_.value().z); - - stat.add("estimated_gyro_bias_x", gyro_bias_.value().x - angular_velocity_offset_x_); - stat.add("estimated_gyro_bias_y", gyro_bias_.value().y - angular_velocity_offset_y_); - stat.add("estimated_gyro_bias_z", gyro_bias_.value().z - angular_velocity_offset_z_); - - // Validation - const bool is_bias_small_enough = - std::abs(gyro_bias_.value().x - angular_velocity_offset_x_) < gyro_bias_threshold_ && - std::abs(gyro_bias_.value().y - angular_velocity_offset_y_) < gyro_bias_threshold_ && - std::abs(gyro_bias_.value().z - angular_velocity_offset_z_) < gyro_bias_threshold_; - - // Update diagnostics - if (is_bias_small_enough) { - stat.add("gyro_bias", "OK"); - stat.summary(diagnostic_msgs::msg::DiagnosticStatus::OK, "OK"); - } else { - stat.add( - "gyro_bias", - "Gyro bias may be incorrect. Please calibrate IMU and reflect the result in " - "imu_corrector. You may also use the output of gyro_bias_estimator."); - stat.summary(diagnostic_msgs::msg::DiagnosticStatus::WARN, "WARN"); - } - } + auto f = [](const double & value) { + std::stringstream ss; + ss << std::fixed << std::setprecision(8) << value; + return ss.str(); + }; + + stat.summary(diagnostics_info_.level, diagnostics_info_.summary_message); + stat.add("gyro_bias_x_for_imu_corrector", f(diagnostics_info_.gyro_bias_x_for_imu_corrector)); + stat.add("gyro_bias_y_for_imu_corrector", f(diagnostics_info_.gyro_bias_y_for_imu_corrector)); + stat.add("gyro_bias_z_for_imu_corrector", f(diagnostics_info_.gyro_bias_z_for_imu_corrector)); + + stat.add("estimated_gyro_bias_x", f(diagnostics_info_.estimated_gyro_bias_x)); + stat.add("estimated_gyro_bias_y", f(diagnostics_info_.estimated_gyro_bias_y)); + stat.add("estimated_gyro_bias_z", f(diagnostics_info_.estimated_gyro_bias_z)); + + stat.add("gyro_bias_threshold", f(gyro_bias_threshold_)); } } // namespace imu_corrector diff --git a/sensing/imu_corrector/src/gyro_bias_estimator.hpp b/sensing/imu_corrector/src/gyro_bias_estimator.hpp index 821cba0b213ff..3592ff1f7d3b4 100644 --- a/sensing/imu_corrector/src/gyro_bias_estimator.hpp +++ b/sensing/imu_corrector/src/gyro_bias_estimator.hpp @@ -49,6 +49,7 @@ class GyroBiasEstimator : public rclcpp::Node void callback_imu(const Imu::ConstSharedPtr imu_msg_ptr); void callback_odom(const Odometry::ConstSharedPtr odom_msg_ptr); void timer_callback(); + void validate_gyro_bias(); static geometry_msgs::msg::Vector3 transform_vector3( const geometry_msgs::msg::Vector3 & vec, @@ -68,6 +69,7 @@ class GyroBiasEstimator : public rclcpp::Node const double angular_velocity_offset_y_; const double angular_velocity_offset_z_; const double timer_callback_interval_sec_; + const double diagnostics_updater_interval_sec_; const double straight_motion_ang_vel_upper_limit_; diagnostic_updater::Updater updater_; @@ -80,6 +82,20 @@ class GyroBiasEstimator : public rclcpp::Node std::vector gyro_all_; std::vector pose_buf_; + + struct DiagnosticsInfo + { + unsigned char level; + std::string summary_message; + double gyro_bias_x_for_imu_corrector; + double gyro_bias_y_for_imu_corrector; + double gyro_bias_z_for_imu_corrector; + double estimated_gyro_bias_x; + double estimated_gyro_bias_y; + double estimated_gyro_bias_z; + }; + + DiagnosticsInfo diagnostics_info_; }; } // namespace imu_corrector From e67ab70f27eaae9f3a0b54b73610737929003c67 Mon Sep 17 00:00:00 2001 From: Esteve Fernandez <33620+esteve@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:41:19 +0100 Subject: [PATCH 041/132] build(yabloc_pose_initializer): fix dependencies (#6190) Signed-off-by: Esteve Fernandez --- localization/yabloc/yabloc_pose_initializer/CMakeLists.txt | 4 ++++ localization/yabloc/yabloc_pose_initializer/package.xml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/localization/yabloc/yabloc_pose_initializer/CMakeLists.txt b/localization/yabloc/yabloc_pose_initializer/CMakeLists.txt index 164f280becae8..91b272b413c4c 100644 --- a/localization/yabloc/yabloc_pose_initializer/CMakeLists.txt +++ b/localization/yabloc/yabloc_pose_initializer/CMakeLists.txt @@ -14,6 +14,9 @@ find_package(PCL REQUIRED COMPONENTS common kdtree) # Sophus find_package(Sophus REQUIRED) +# OpenCV +find_package(OpenCV REQUIRED) + # =================================================== # Executable # Camera @@ -28,6 +31,7 @@ ament_auto_add_executable(${TARGET} target_include_directories(${TARGET} PUBLIC include) target_include_directories(${TARGET} SYSTEM PRIVATE ${EIGEN3_INCLUDE_DIRS} ${PCL_INCLUDE_DIRS}) target_link_libraries(${TARGET} ${PCL_LIBRARIES} Sophus::Sophus) +ament_target_dependencies(${TARGET} OpenCV) # =================================================== ament_auto_package(INSTALL_TO_SHARE config launch) diff --git a/localization/yabloc/yabloc_pose_initializer/package.xml b/localization/yabloc/yabloc_pose_initializer/package.xml index e9921db50093e..afd0d4aa86bcf 100644 --- a/localization/yabloc/yabloc_pose_initializer/package.xml +++ b/localization/yabloc/yabloc_pose_initializer/package.xml @@ -17,8 +17,10 @@ rosidl_default_generators autoware_auto_mapping_msgs + cv_bridge geometry_msgs lanelet2_extension + libopencv-dev rclcpp sensor_msgs tier4_localization_msgs From 59e869666a985e1bd63f1389a0176c2909c7aa6e Mon Sep 17 00:00:00 2001 From: Mamoru Sobue Date: Mon, 29 Jan 2024 22:15:57 +0900 Subject: [PATCH 042/132] fix(intersection): judge pass judge at intersection without tl with occlusion detection (#6207) Signed-off-by: Mamoru Sobue --- .../src/decision_result.cpp | 14 ++++---- .../src/scene_intersection.cpp | 33 ++++++++++++++++--- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/planning/behavior_velocity_intersection_module/src/decision_result.cpp b/planning/behavior_velocity_intersection_module/src/decision_result.cpp index 93a7c2a29d2f7..aefd59a72f9b4 100644 --- a/planning/behavior_velocity_intersection_module/src/decision_result.cpp +++ b/planning/behavior_velocity_intersection_module/src/decision_result.cpp @@ -19,11 +19,11 @@ namespace behavior_velocity_planner::intersection std::string formatDecisionResult(const DecisionResult & decision_result) { if (std::holds_alternative(decision_result)) { - const auto state = std::get(decision_result); + const auto & state = std::get(decision_result); return "InternalError because " + state.error; } if (std::holds_alternative(decision_result)) { - const auto state = std::get(decision_result); + const auto & state = std::get(decision_result); return "OverPassJudge:\nsafety_report:" + state.safety_report + "\nevasive_report:\n" + state.evasive_report; } @@ -31,11 +31,11 @@ std::string formatDecisionResult(const DecisionResult & decision_result) return "StuckStop"; } if (std::holds_alternative(decision_result)) { - const auto state = std::get(decision_result); + const auto & state = std::get(decision_result); return "YieldStuckStop:\nsafety_report:" + state.safety_report; } if (std::holds_alternative(decision_result)) { - const auto state = std::get(decision_result); + const auto & state = std::get(decision_result); return "NonOccludedCollisionStop\nsafety_report:" + state.safety_report; } if (std::holds_alternative(decision_result)) { @@ -45,18 +45,18 @@ std::string formatDecisionResult(const DecisionResult & decision_result) return "PeekingTowardOcclusion"; } if (std::holds_alternative(decision_result)) { - const auto state = std::get(decision_result); + const auto & state = std::get(decision_result); return "OccludedCollisionStop\nsafety_report:" + state.safety_report; } if (std::holds_alternative(decision_result)) { - const auto state = std::get(decision_result); + const auto & state = std::get(decision_result); return "OccludedAbsenceTrafficLight\nsafety_report:" + state.safety_report; } if (std::holds_alternative(decision_result)) { return "Safe"; } if (std::holds_alternative(decision_result)) { - const auto state = std::get(decision_result); + const auto & state = std::get(decision_result); return "FullyPrioritized\nsafety_report:" + state.safety_report; } return ""; diff --git a/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp b/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp index 75e2da034780a..3f6136673a44a 100644 --- a/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp +++ b/planning/behavior_velocity_intersection_module/src/scene_intersection.cpp @@ -354,8 +354,18 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( : false; if (!has_traffic_light_) { if (fromEgoDist(occlusion_wo_tl_pass_judge_line_idx) < 0) { - return intersection::InternalError{ - "already passed maximum peeking line in the absence of traffic light"}; + if (has_collision) { + const auto closest_idx = intersection_stoplines.closest_idx; + const std::string evasive_diag = generateEgoRiskEvasiveDiagnosis( + *path, closest_idx, time_distance_array, too_late_detect_objects, misjudge_objects); + return intersection::OverPassJudge{ + "already passed maximum peeking line in the absence of traffic light.\n" + + safety_report, + evasive_diag}; + } + return intersection::OverPassJudge{ + "already passed maximum peeking line in the absence of traffic light safely", + "no evasive action required"}; } return intersection::OccludedAbsenceTrafficLight{ is_occlusion_cleared_with_margin, @@ -364,7 +374,7 @@ intersection::DecisionResult IntersectionModule::modifyPathVelocityDetail( closest_idx, first_attention_stopline_idx, occlusion_wo_tl_pass_judge_line_idx, - safety_report}; + safety_diag}; } // ========================================================================================== @@ -1251,7 +1261,22 @@ IntersectionModule::PassJudgeStatus IntersectionModule::isOverPassJudgeLinesStat return first_pass_judge_line_idx; }(); - const bool was_safe = std::holds_alternative(prev_decision_result_); + // ========================================================================================== + // at intersection without traffic light, this module ignores occlusion even if occlusion is + // detected for real, so if collision is not detected in that context, that should be interpreted + // as "was_safe" + // ========================================================================================== + const bool was_safe = [&]() { + if (std::holds_alternative(prev_decision_result_)) { + return true; + } + if (std::holds_alternative(prev_decision_result_)) { + const auto & state = + std::get(prev_decision_result_); + return !state.collision_detected; + } + return false; + }(); const bool is_over_1st_pass_judge_line = util::isOverTargetIndex(path, closest_idx, current_pose, pass_judge_line_idx); From 4f7fded30f48d3017dcf8da291fdbd429bdb130a Mon Sep 17 00:00:00 2001 From: Satoshi Tanaka <16330533+scepter914@users.noreply.github.com> Date: Mon, 29 Jan 2024 22:25:57 +0900 Subject: [PATCH 043/132] chore(simple_object_merger): fix README (#6202) * chore(simple_object_merger): fix README Signed-off-by: scepter914 * style(pre-commit): autofix --------- Signed-off-by: scepter914 Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- perception/simple_object_merger/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/perception/simple_object_merger/README.md b/perception/simple_object_merger/README.md index 9bcd03e8abfa1..4c037963361a1 100644 --- a/perception/simple_object_merger/README.md +++ b/perception/simple_object_merger/README.md @@ -1,23 +1,21 @@ # simple_object_merger -This package can merge multiple topics of [autoware_auto_perception_msgs/msg/DetectedObject](https://gitlab.com/autowarefoundation/autoware.auto/autoware_auto_msgs/-/blob/master/autoware_auto_perception_msgs/msg/DetectedObject.idl) without low calculation cost. +This package can merge multiple topics of [autoware_auto_perception_msgs/msg/DetectedObject](https://gitlab.com/autowarefoundation/autoware.auto/autoware_auto_msgs/-/blob/master/autoware_auto_perception_msgs/msg/DetectedObject.idl) with low calculation cost. -## Algorithm +## Design ### Background [Object_merger](https://github.com/autowarefoundation/autoware.universe/tree/main/perception/object_merger) is mainly used for merge process with DetectedObjects. There are 2 characteristics in `Object_merger`. First, `object_merger` solve data association algorithm like Hungarian algorithm for matching problem, but it needs computational cost. Second, `object_merger` can handle only 2 DetectedObjects topics and cannot handle more than 2 topics in one node. To merge 6 DetectedObjects topics, 6 `object_merger` nodes need to stand for now. -So `simple_object_merger` aim to merge multiple DetectedObjects with low calculation cost. +Therefore, `simple_object_merger` aim to merge multiple DetectedObjects with low calculation cost. The package do not use data association algorithm to reduce the computational cost, and it can handle more than 2 topics in one node to prevent launching a large number of nodes. ### Use case -Use case is as below. - - Multiple radar detection -`Simple_object_merger` can be used for multiple radar detection. By combining them into one topic from multiple radar topics with `simple_object_merger`, the pipeline for faraway detection with radar is simpler. +`Simple_object_merger` can be used for multiple radar detection. By combining them into one topic from multiple radar topics, the pipeline for faraway detection with radar can be simpler. ### Limitation From ba21eecc260051a0d7c7e8d0108f833d75d58192 Mon Sep 17 00:00:00 2001 From: Khalil Selyan <36904941+KhalilSelyan@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:49:49 +0300 Subject: [PATCH 044/132] feat: new rviz ui - speed/gear/turnsignal/steering (#5957) Signed-off-by: Khalil Selyan --- .../awf_2d_overlay_vehicle/CMakeLists.txt | 140 +++++ .../awf_2d_overlay_vehicle/LICENSE | 12 + .../awf_2d_overlay_vehicle/README.md | 54 ++ .../assets/font/Quicksand/LICENSE | 93 +++ .../font/Quicksand/static/Quicksand-Bold.ttf | Bin 0 -> 78596 bytes .../font/Quicksand/static/Quicksand-Light.ttf | Bin 0 -> 78660 bytes .../Quicksand/static/Quicksand-Medium.ttf | Bin 0 -> 78948 bytes .../Quicksand/static/Quicksand-Regular.ttf | Bin 0 -> 78936 bytes .../Quicksand/static/Quicksand-SemiBold.ttf | Bin 0 -> 78820 bytes .../assets/images/arrow.png | Bin 0 -> 260 bytes .../assets/images/select_add.png | Bin 0 -> 18359 bytes .../assets/images/select_topic_name.png | Bin 0 -> 422591 bytes .../assets/images/select_vehicle_plugin.png | Bin 0 -> 72553 bytes .../assets/images/traffic.png | Bin 0 -> 622 bytes .../assets/images/wheel.png | Bin 0 -> 1632 bytes .../awf_2d_overlay_vehicle-extras.cmake | 31 + .../include/gear_display.hpp | 49 ++ .../include/overlay_text_display.hpp | 157 +++++ .../include/overlay_utils.hpp | 141 +++++ .../include/signal_display.hpp | 124 ++++ .../include/speed_display.hpp | 49 ++ .../include/speed_limit_display.hpp | 49 ++ .../include/steering_wheel_display.hpp | 54 ++ .../include/traffic_display.hpp | 62 ++ .../include/turn_signals_display.hpp | 63 ++ .../awf_2d_overlay_vehicle/package.xml | 31 + .../plugins_description.xml | 5 + .../src/gear_display.cpp | 98 +++ .../src/overlay_text_display.cpp | 556 ++++++++++++++++++ .../src/overlay_utils.cpp | 267 +++++++++ .../src/signal_display.cpp | 501 ++++++++++++++++ .../src/speed_display.cpp | 109 ++++ .../src/speed_limit_display.cpp | 105 ++++ .../src/steering_wheel_display.cpp | 123 ++++ .../src/traffic_display.cpp | 113 ++++ .../src/turn_signals_display.cpp | 122 ++++ .../rviz_2d_overlay_msgs/CHANGELOG.rst | 24 + .../rviz_2d_overlay_msgs/CMakeLists.txt | 19 + .../rviz_2d_overlay_msgs/msg/OverlayText.msg | 31 + .../rviz_2d_overlay_msgs/package.xml | 24 + 40 files changed, 3206 insertions(+) create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/CMakeLists.txt create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/LICENSE create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/README.md create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/LICENSE create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Bold.ttf create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Light.ttf create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Medium.ttf create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Regular.ttf create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-SemiBold.ttf create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/arrow.png create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/select_add.png create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/select_topic_name.png create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/select_vehicle_plugin.png create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/traffic.png create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/wheel.png create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/awf_2d_overlay_vehicle-extras.cmake create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/gear_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/overlay_text_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/overlay_utils.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/signal_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/speed_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/speed_limit_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/steering_wheel_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/traffic_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/include/turn_signals_display.hpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/package.xml create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/plugins_description.xml create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/gear_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/overlay_text_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/overlay_utils.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/signal_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/speed_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/speed_limit_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/steering_wheel_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/traffic_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/src/turn_signals_display.cpp create mode 100644 common/awf_vehicle_rviz_plugin/rviz_2d_overlay_msgs/CHANGELOG.rst create mode 100644 common/awf_vehicle_rviz_plugin/rviz_2d_overlay_msgs/CMakeLists.txt create mode 100644 common/awf_vehicle_rviz_plugin/rviz_2d_overlay_msgs/msg/OverlayText.msg create mode 100644 common/awf_vehicle_rviz_plugin/rviz_2d_overlay_msgs/package.xml diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/CMakeLists.txt b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/CMakeLists.txt new file mode 100644 index 0000000000000..da67a6f63aeae --- /dev/null +++ b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/CMakeLists.txt @@ -0,0 +1,140 @@ +cmake_minimum_required(VERSION 3.8) +project(awf_2d_overlay_vehicle) + +# find dependencies +find_package(ament_cmake_auto REQUIRED) +find_package(ament_cmake REQUIRED) +find_package(autoware_auto_vehicle_msgs REQUIRED) +find_package(tier4_planning_msgs REQUIRED) +find_package(autoware_perception_msgs REQUIRED) +ament_auto_find_build_dependencies() + +find_package(rviz_2d_overlay_msgs REQUIRED) + +find_package(rviz_common REQUIRED) +find_package(rviz_rendering REQUIRED) +find_package(rviz_ogre_vendor REQUIRED) +find_package(std_msgs REQUIRED) + +set( + headers_to_moc + include/overlay_text_display.hpp + include/signal_display.hpp + +) + +set( + headers_to_not_moc + include/steering_wheel_display.hpp + include/gear_display.hpp + include/speed_display.hpp + include/turn_signals_display.hpp + include/traffic_display.hpp + include/speed_limit_display.hpp +) + + + +foreach(header "${headers_to_moc}") + qt5_wrap_cpp(display_moc_files "${header}") +endforeach() + +set( + display_source_files + src/overlay_text_display.cpp + src/overlay_utils.cpp + src/signal_display.cpp + src/steering_wheel_display.cpp + src/gear_display.cpp + src/speed_display.cpp + src/turn_signals_display.cpp + src/traffic_display.cpp + src/speed_limit_display.cpp + +) + +add_library( + ${PROJECT_NAME} SHARED + ${display_moc_files} + ${headers_to_not_moc} + ${display_source_files} +) + +set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17) +target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic) + +target_include_directories( + ${PROJECT_NAME} PUBLIC + $ + $ + ${Qt5Widgets_INCLUDE_DIRS} + ${OpenCV_INCLUDE_DIRS} +) + +target_link_libraries( + ${PROJECT_NAME} PUBLIC + rviz_ogre_vendor::OgreMain + rviz_ogre_vendor::OgreOverlay +) + + +target_compile_definitions(${PROJECT_NAME} PRIVATE "${PROJECT_NAME}_BUILDING_LIBRARY") + +# prevent pluginlib from using boost +target_compile_definitions(${PROJECT_NAME} PUBLIC "PLUGINLIB__DISABLE_BOOST_FUNCTIONS") + +pluginlib_export_plugin_description_file(rviz_common plugins_description.xml) + +ament_target_dependencies( + ${PROJECT_NAME} + PUBLIC + rviz_common + rviz_rendering + rviz_2d_overlay_msgs + autoware_auto_vehicle_msgs + tier4_planning_msgs + autoware_perception_msgs +) + +ament_export_include_directories(include) +ament_export_targets(${PROJECT_NAME} HAS_LIBRARY_TARGET) +ament_export_dependencies( + rviz_common + rviz_ogre_vendor +) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + ament_lint_auto_find_test_dependencies() +endif() + +install( + TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + INCLUDES DESTINATION include +) + +install( + DIRECTORY include/ + DESTINATION include +) + +install( + TARGETS + DESTINATION lib/${PROJECT_NAME} +) + +# Copy the assets directory to the installation directory +install( + DIRECTORY assets/ + DESTINATION share/${PROJECT_NAME}/assets +) + +add_definitions(-DQT_NO_KEYWORDS) + +ament_package( + CONFIG_EXTRAS "awf_2d_overlay_vehicle-extras.cmake" +) diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/LICENSE b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/LICENSE new file mode 100644 index 0000000000000..a2fe2d3d1c7ed --- /dev/null +++ b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/LICENSE @@ -0,0 +1,12 @@ +Copyright (c) 2022, Team Spatzenhirn +Copyright (c) 2014, JSK Lab + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/README.md b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/README.md new file mode 100644 index 0000000000000..6728f26878e10 --- /dev/null +++ b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/README.md @@ -0,0 +1,54 @@ +# awf_2d_overlay_vehicle + +Plugin for displaying 2D overlays over the RViz2 3D scene. + +Based on the [jsk_visualization](https://github.com/jsk-ros-pkg/jsk_visualization) +package, under the 3-Clause BSD license. + +## Purpose + +This plugin provides a visual and easy-to-understand display of vehicle speed, turn signal, steering status and gears. + +## Inputs / Outputs + +### Input + +| Name | Type | Description | +| ---------------------------------------- | ------------------------------------------------------- | ---------------------------------- | +| `/vehicle/status/velocity_status` | `autoware_auto_vehicle_msgs::msg::VelocityReport` | The topic is vehicle twist | +| `/vehicle/status/turn_indicators_status` | `autoware_auto_vehicle_msgs::msg::TurnIndicatorsReport` | The topic is status of turn signal | +| `/vehicle/status/hazard_status` | `autoware_auto_vehicle_msgs::msg::HazardReport` | The topic is status of hazard | +| `/vehicle/status/steering_status` | `autoware_auto_vehicle_msgs::msg::SteeringReport` | The topic is status of steering | +| `/vehicle/status/gear_status` | `autoware_auto_vehicle_msgs::msg::GearReport` | The topic is status of gear | + +## Parameter + +### Core Parameters + +#### SignalDisplay + +| Name | Type | Default Value | Description | +| ------------------------ | ------ | -------------------- | --------------------------------- | +| `property_width_` | int | 128 | Width of the plotter window [px] | +| `property_height_` | int | 128 | Height of the plotter window [px] | +| `property_left_` | int | 128 | Left of the plotter window [px] | +| `property_top_` | int | 128 | Top of the plotter window [px] | +| `property_signal_color_` | QColor | QColor(25, 255, 240) | Turn Signal color | + +## Assumptions / Known limits + +TBD. + +## Usage + +1. Start rviz and select Add under the Displays panel. + + ![select_add](./assets/images/select_add.png) + +2. Select any one of the tier4_vehicle_rviz_plugin and press OK. + + ![select_vehicle_plugin](./assets/images/select_vehicle_plugin.png) + +3. Enter the name of the topic where you want to view the status. + + ![select_topic_name](./assets/images/select_topic_name.png) diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/LICENSE b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/LICENSE new file mode 100644 index 0000000000000..cc04d393573f0 --- /dev/null +++ b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/LICENSE @@ -0,0 +1,93 @@ +Copyright 2011 The Quicksand Project Authors (https://github.com/andrew-paglinawan/QuicksandFamily), with Reserved Font Name “Quicksand”. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Bold.ttf b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..07d5127c04b17a9a62121d12aeb00b701e920500 GIT binary patch literal 78596 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 Jl2>2&{{USQh2;PM literal 0 HcmV?d00001 diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Light.ttf b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..800531084fa6cecc3b7ee732bc66582d0f889aed GIT binary patch literal 78660 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 literal 0 HcmV?d00001 diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Medium.ttf b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/font/Quicksand/static/Quicksand-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f4634cd7c3f16e8b1ffd01f2ea4a824b3b25991d GIT binary patch literal 78948 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 E0R8`9>Hq)$ literal 0 HcmV?d00001 diff --git a/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/select_add.png b/common/awf_vehicle_rviz_plugin/awf_2d_overlay_vehicle/assets/images/select_add.png new file mode 100644 index 0000000000000000000000000000000000000000..c5130b6092384e5477ca0c52e856eee862f69431 GIT binary patch literal 18359 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%0A(tv^0UFx5qxWpi+PKZsX*+Bw&>V%RJ2^AFr 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
iQinPRE~JVt+BVN1ZHRQ5aKcGwaRQ7LO9 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

A(*5UFM@5DKo)sZdQB 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

Dd&b?LOYG)b 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Μ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